typescript对象类型的关键字

mum43rcc  于 2023-10-22  发布在  TypeScript
关注(0)|答案(3)|浏览(181)

我有这个:

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'仅引用类型,但在此处用作值。

w6mmgewl

w6mmgewl1#

您还需要为重命名的属性使用Map类型:

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

5w9g7ksd2#

在当前的typescript版本4.6.2中,有一个重Map语法可供使用。它可以更容易地实现这一点。
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可以用。用于根据条件类型重命名KeyK
  3. K extends keyof T. keyof T表示three | five
  4. T[K] extends string表示T[K]是字符串。T['three']是字符串,所以返回fourT['five']返回nouse;
    1.返回类型K extends keyof U,所以T['three']被满足,所以返回{ four: U['three'] }意味着{ four: boolean}
    1.其他键作为原点返回
    参考文献:
    https://github.com/microsoft/TypeScript/issues/40833https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
6jjcrrmo

6jjcrrmo3#

也许值得一提的是,您可以解决OP的原始问题,而无需编写像Rename这样的泛型类型。如果你只想做一次,你可以做一些更简单的事情。

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

相关问题