更改 Typescript 映射类型中的属性名称

2024-03-11

我有一个 Typescript 对象的集合,如下所示:

SomeData {
  prop1: string;
  prop2: number;
}

我需要最终得到一些如下所示的对象:

type SomeMoreData= {
  prop1Change: string;
  prop2Change: number;
}

我知道如果我只是想改变类型,我可以这样做:

type SomeMoreData<T> = {
  [P in keyof T]: boolean;
}

这会给我:

SomeMoreData<SomeData> {
  prop1: boolean;
  prop2: boolean;
}

有没有办法操纵由[P in keyof T]少量?我尝试过类似的事情[(P in keyof T) + "Change"]没有成功。


TS4.1 之前的答案;

你不能自动完成它。最大的障碍是目前无类型运算符 https://github.com/Microsoft/TypeScript/issues/16392它允许您在类型级别附加字符串文字,因此您甚至无法描述您正在执行的转换:

// without Append<A extends string, B extends string>, you can't type this:

function appendChange<T extends string>(originalKey: T): Append<T,'Change'> {
  return originalKey+'Change';
}

有一个建议 https://github.com/Microsoft/TypeScript/issues/12754对于这个功能,但谁知道它是否会发生。

这意味着如果你想转换键,你需要实际硬编码你正在寻找的特定映射,从字符串文字到字符串文字:

type SomeMoreDataMapping = {
  prop1: "prop1Change"
  prop2: "prop2Change"
}

有了这个映射,您就可以定义这些:

type ValueOf<T> = T[keyof T]
type KeyValueTupleToObject<T extends [keyof any, any]> = {
  [K in T[0]]: Extract<T, [K, any]>[1]
}
type MapKeys<T, M extends Record<string, string>> =
  KeyValueTupleToObject<ValueOf<{
    [K in keyof T]: [K extends keyof M ? M[K] : K, T[K]]
  }>>

简要介绍:

  • ValueOf<T>仅返回 type 的属性值类型的并集T.
  • KeyValueTupleToObject采用元组类型的并集,如下所示:["a",string] | ["b",number]并将它们变成这样的对象类型:{a: string, b: number}.
  • And MapKeys<T, M>需要一个类型T和键映射M并替换任意键T它存在于M与相应的密钥M。如果输入一个键T不存在于M,密钥未变换。如果输入一个键M不存在于T,它将被忽略。

现在你(终于)可以这样做:

type SomeMoreData= MapKeys<SomeData, SomeMoreDataMapping>;

如果你检查SomeMoreData,你会看到它有正确的类型:

var someMoreData: SomeMoreData = {
  prop1Change: 'Mystery Science Theater',
  prop2Change: 3000
} // type checks

这应该允许您做一些有趣的事情,例如:

function makeTheChange<T>(input: T): MapKeys<T, SomeMoreDataMapping> {
  var ret = {} as MapKeys<T, SomeMoreDataMapping>;
  for (var k in input) {
    // lots of any needed here; hard to convince the type system you're doing the right thing
    var nk: keyof typeof ret = <any>((k === 'prop1') ? 'prop1Change' : (k === 'prop2') ? 'prop2Change' : k);
    ret[nk] = <any>input[k];    
  }
  return ret;
}

var changed = makeTheChange({ prop1: 'Gypsy', prop2: 'Tom', prop3: 'Crow' });
console.log(changed.prop1Change.charAt(0)); //ok
console.log(changed.prop2Change.charAt(0)); //ok
console.log(changed.prop3.charAt(0)); //ok

希望有帮助。祝你好运!

UPDATED SEP 2018 to use advantage of conditional types https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#conditional-types introduced with TS 2.8


另一个更新:如果您希望它与可选属性一起使用,它会变得更加复杂:

type RequiredKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? never : K }[keyof T];
type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T];
type MapKeys<T, M extends Record<string, string>> =
  KeyValueTupleToObject<ValueOf<{
    [K in RequiredKeys<T>]-?: [K extends keyof M ? M[K] : K, T[K]]
  }>> & Partial<KeyValueTupleToObject<ValueOf<{
    [K in OptionalKeys<T>]-?: [K extends keyof M ? M[K] : K, T[K]]
  }>>> extends infer O ? { [K in keyof O]: O[K] } : never;

如果您需要支持索引签名,那就会变得更加复杂。

Playground 代码链接 https://www.typescriptlang.org/play/#code/C4TwDgpgBAyg9gWwgWTgJwgEQIbG87MMASwDsBzKAXigG8AoKKMNOMARgC4oAiFt9gGEAFtgoQejZqzAAmbnxmyRY8hPoBfevVCQoANWwAbAK4QA8gDMAPABUAfNSi2A2gGsIIOJecBdHeDQANKehqYQtiZgRhFw5gBGAFYQAMbAdlAQAB7AEKQAJgDOUO6e3lBiIAA0FaQgvo40DEwuQVBkzi4ADL6+3ACiOWjYaXY1rTWVDS7s-lq60ARgISCFY1DImTl5RVAASqno+daFwGhk5DWn5xT2jVIrYWaR0bEJyaNPFjbNTCVtHQOAEcTMQMPkVmsHL4ALQAfm4rS2uQKxQ8Xh8mzhG1avig3CCNVcQV6Ug0dygADIoAAFbBoYDEYzWR7GZ5RGK2OJJVLpL5Way-FoA0hQcxgRlwUjGSF2eywhH-ZE7NFlTFQbHIXH4qCEzok-xMckU7Io3ZkSwQNBijV0JUddHlcx9MXajQ60gQABuVoA3NoFvsICCwRAIZ4oY07UiHWq-PDuLR3aaVbTiCk3Osgo5sZ6fdaCVANKUMX5-YHxZLpUZZQ4nLR7aLHT5bArE8ntqi0xmszndR7vVaiyXyq3-fQyLk0JYRtB4EgcHg6FJ+BxFdcLv6mKv5FBSCYEPE-SuZABmddnTcntgAFm4+8Px60AT085Q6CwuGwTiWsrfi+wGo31QDAAKWEhbl9IA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更改 Typescript 映射类型中的属性名称 的相关文章

随机推荐