'Rename key of typescript object type

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.



Solution 1:[1]

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;
// }

Solution 2:[2]

In the current typescript version 4.6.2, there is a remapping gramma to use. It can be implement this much easier.

PlayGround

type RenameByT<T, U> = {
  [K in keyof U as K extends keyof T
    ? T[K] extends string
      ? T[K]
      : never
    : K]: K extends keyof U ? U[K] : never;
};

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

// retrunType = { one: number; two: string, four: boolean };
type renameOne = RemaneByT<{three: 'four', five: 'nouse'}, Two>;

// returnType = { x: number, y: string, z: boolean; }
type renameAll = RenameByT<{one: 'x', two: 'y', three: 'z'}, Two>;

The RenameByT type can separate by several parts. The explain is for the example renameOne

  1. K in keyof U means all the key in U. For the example is one | two | three
  2. as clause since ts4.1 can use. but i can't use in 4.4.4 but can use in 4.6.2. This is use to rename Key K by the condiction type
  3. K extends keyof T. keyof T means three | five.
  4. T[K] extends string means T[K] is string. T['three'] is string so returns four, T['five'] returns nouse;
  5. the return type K extends keyof U, so T['three'] is satisfy so return { four: U['three'] } means { four: boolean}
  6. ohters keys return as origin

reference:

https://github.com/microsoft/TypeScript/issues/40833 https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Titian Cernicova-Dragomir
Solution 2