Home > front end >  TypeScript Generic to change all types of a particular type to another
TypeScript Generic to change all types of a particular type to another

Time:09-17

I'm trying to come up with a typescript type that takes an object and sets all keys of type number to be string. The following doesn't work:

export type ChangeTypeOfKeys<T extends object> = {
  [key in keyof T]: key extends number ? string : T[key]
}

const c: ChangeTypeOfKeys<{ a: number, b: boolean }> = {
    a: 'ok',
    b: false,
}

The resulting type should be { a: string, b: boolean }, but instead I get a TS error:

Type 'string' is not assignable to type 'number'.(2322)
input.tsx(5, 29): The expected type comes from property 'a' which is declared here on type 'ChangeTypeOfKeys<{ a: number; b: boolean; }>'

TS playground link

I think the issue is related to how I'm using key in key in keyof T, since replacing key extends number with another argument works:

export type ChangeTypeOfKeys<T extends object, Replace> = {
  [key in keyof T]: Replace extends number ? string : T[key]
}

const c: ChangeTypeOfKeys<{ a: number, b: boolean }, number> = {
    a: 'ok',
    b: 'ok',
}

TS playground link

Not sure if there are any special properties with key that I'm missing here. TIA!

CodePudding user response:

To get the value of property referenced by key, do this:

export type ChangeTypeOfKeys<T extends object> = {
  [key in keyof T]: T[key] extends number ? string : T[key]
  //                ^^^^^^
}

Playground Link


The type of key will always be string in the example you gave. To be absolutely clear, in your code:

  • key refers to the name of a property,
  • T[key] refers to the property named key on type T.

Also note, extends object allows for [] types (among others), which might not be what you want. Try extending from {} or Record<string, any> instead.

  • Related