你可以排序做你想要的,但不是自动的。大阻滞剂是,目前还no type operator,让您在类型级别追加字符串文字,所以你甚至不能形容你在做转型:这意味着你需要真正的硬编码
// 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';
}
你正在寻找的具体映射,从字符串文字到字符串文字。事实上,我能得到这个工作的唯一方法是指定反向映射:
type SomeMoreDataMapping = {
prop1Change: 'prop1';
prop2Change: 'prop2';
}
武装与反向映射,您可以定义这些:
type Diff<T extends string, U extends string> = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]};
type Dict<T> = { [k: string]: T };
type MapKeys<T extends Dict<any>, M extends Dict<string>> = {
[K in keyof M]: T[M[K]];
} & Omit<T, M[keyof M]>;
(其中一些是。需要打字稿V2.4及以上如果您使用的打字稿的早期版本,请参阅this issue的方式来实现Diff
和Omit
)
简要runthrough:
Diff<T,U>
对字符串文字类型的联合起作用,将U
中的那些从T
中的那些中删除。
Omit<T,K>
从对象类型T
中删除K
中的所有属性。
Dict<T>
只是一个字符串键的对象,其属性都是T
。
- 最后是
MapKeys<T,M>
是你想要的东西:它需要对象T
并根据M
中的反向映射来转换密钥。如果密钥T
不存在于M
中,则密钥不会被转换。如果M
中的密钥不存在于T
中,它将出现在带有any
类型的输出中。
现在你可以(终于)做到这一点:
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
希望有帮助。祝你好运!
循环播放SomeData []并填充SomeMoreData []是一个选项。 – adiga
这不会给我类型验证问题吗?我试图避免在那里有一个“任何”对象。 – Tony