I'm trying to write a type that can strip a given prefix from the keys of another type.
I've tried the following code:
type StripPrefix<
TPrefix extends string,
T extends `${TPrefix}.${string}`,
> = T extends `${TPrefix}.${infer R}` ? R : never;
type MapKeysStripPrefix<T, TPrefix extends string> = {
[K in StripPrefix<TPrefix, keyof T & `${TPrefix}.${string}`>]: Pick<
T,
keyof T & `${TPrefix}.${string}`
>[`${TPrefix}.${K}`];
};
type test = {
'test.blah': 1;
'test.foo': 2;
'bar.baz': 3;
};
type result = MapKeysStripPrefix<test, 'test'>;
But I get an error:
Type '`${TPrefix}.${K}`' cannot be used to index type 'Pick<T, keyof T & `${TPrefix}.${string}`>'
I realize it might not be possible to do.
CodePudding user response:
If you take advantage of key remapping via as
then this is a lot easier:
type StripPrefix<
TPrefix extends string,
T extends string, // changed this constraint to string
> = T extends `${TPrefix}.${infer R}` ? R : never;
type MapKeysStripPrefix<T, TPrefix extends string> = {
[K in keyof T & string as StripPrefix<TPrefix, K>]: T[K];
};
Here we map over the keys of T
intersected with string
to make sure we only have string keys. Then rename those with as
to StripPrefix<TPrefix, K>
which will return either the unprefixed string, or removes it form the resul by returning never
.
And the value type is simply T[K]
which is the value type of the original prefixed property.
CodePudding user response:
The key is to retain intermediate type argument K
so that you can use it to index the record for value.
type StripPrefix<
TPrefix extends string,
T extends `${TPrefix}.${string}`,
> = T extends `${TPrefix}.${infer R}` ? R : never;
type MapKeysStripPrefix<T, P extends string> = {
[K in keyof T & `${P}.${string}`]: { [N in StripPrefix<P, K>]: T[K] }
}[keyof T & `${P}.${string}`]
type test = {
'test.blah': 1;
'test.foo': 2;
'bar.baz': 3;
'kk': 5
};
type R = MapKeysStripPrefix<test, 'test'>;
let rec: R = {blah: 1, foo: 2}