重命名 TypeScript 对象类型的键

17

我有这个:

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

我希望它能创建一个类似于这样的类型:
type RenamedTwo = {
  one: number,
  two: string,
  four: boolean // difference
}

尝试以这种方式创建:

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

为了尝试使用这种方式:

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

但是TSlint标记[N]为错误,并给出以下错误消息:

[ts]类型文字中的计算属性名称必须引用其类型为文字类型或“唯一符号”类型的表达式。 [ts] 'N'只是一个类型的引用,但在此处被用作值。


如果有人想要重命名多个属性,这是类型定义:type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & Record<N, valueof<Pick<T, K>>> - Eduard
3个回答

21
您需要为重命名的属性使用映射类型:
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'>

请注意,如果您提供更多的属性,则此方法不会按预期工作:
type Renamed = Rename<Two, 'two'  |'three' , 'four' | 'five'> // will be Pick<Two, "one"> & {
//    four: string | boolean;
//    five: string | boolean;
// }

1
谢谢!特别感谢您的留言。我根据您的反馈调整了类型定义:type Rename<T, K extends keyof T, N extends string> = Pick<T, Exclude<keyof T, K>> & Record<N, valueof<Pick<T, K>>> - Eduard
太棒了。今天我学到了在string类型中可以使用in运算符,或者即使它是字符串类型,Typescript也会将其读取为联合类型? - The.Wolfgang.Grimmer

11
在当前的TypeScript版本4.6.2中,有一个重新映射语法可以使用。 这样可以更容易地实现它。 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 };

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

// returnType = { x: number, y: string, z: boolean; }
type renameAll = RenameByT<{one: 'x', two: 'y', three: 'z'}, Two>;
RenameByT 类型可以分为几个部分。 这个解释是针对示例 renameOne 的。
  1. K in keyof U 表示 U 中的所有键。例如,one | two | three
  2. as 从 ts4.1 开始可以使用。但我无法在 4.4.4 中使用,但可以在 4.6.2 中使用。这用于根据条件类型重命名 Key K
  3. K extends keyof T。keyof T 表示 three | five
  4. T[K] extends string 表示 T[K] 是字符串。 T['three'] 是字符串,所以返回 fourT['five'] 返回 nouse
  5. 返回类型为 K extends keyof U,所以 T['three'] 符合条件,因此返回 { four: U['three'] } 表示 { four: boolean}
  6. 其他键返回原始值

参考:

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


1

值得一提的是,您可以在不编写类似于Rename的通用类型的情况下解决原问题。如果您只想执行一次操作,那么可以使用更简单的方法。

type RenamedTwo = { [Property in keyof Two as Property extends 'three' ? 'four': Property]:  Two[Property] }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接