Home > Enterprise >  How to write a TypeScript type that strips a prefix from the keys of another type
How to write a TypeScript type that strips a prefix from the keys of another type

Time:06-04

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.

Playground

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}

Playground

  • Related