10
votes

I have this:

type Two = {
  one: number,
  two: string,
  three: boolean
}

I want it to create a type that would look like this:

type RenamedTwo = {
  one: number,
  two: string,
  four: boolean // difference
}

Tried to create it this way:

type Rename<T, K extends keyof T, N> = Pick<T, Exclude<keyof T, K>> & { [N]: T[K] }

In an attempt to use this way:

type Renamed = Rename<Two, 'three', 'four'>

But TSlint marks [N] as error and gives this error message:

[ts] A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type. [ts] 'N' only refers to a type, but is being used as a value here.

1
In case someone wants to rename multiple properties, here is the type definition: type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & Record<N, valueof<Pick<T, K>>>Eduard

1 Answers

13
votes

You need to use a mapped type for the renamed property as well:

type Two = {
    one: number,
    two: string,
    three: boolean
}


type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & { [P in N]: T[K] }

type Renamed = Rename<Two, 'three', 'four'>

Note that this will not work as expected if you provide more properties:

type Renamed = Rename<Two, 'two'  |'three' , 'four' | 'five'> // will be Pick<Two, "one"> & {
//    four: string | boolean;
//    five: string | boolean;
// }