2017-06-02 175 views
4

我打字稿对象的集合,它是这样的:在打字稿映射类型更改属性名称

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"]这样的事情,但没有成功。

+0

循环播放SomeData []并填充SomeMoreData []是一个选项。 – adiga

+0

这不会给我类型验证问题吗?我试图避免在那里有一个“任何”对象。 – Tony

回答

2

你可以排序做你想要的,但不是自动的。大阻滞剂是,目前还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的方式来实现DiffOmit

简要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 

希望有帮助。祝你好运!

+0

如果您事先不知道该物业的名称,并且想要为每个物业添加另一个属性,则该物业的类型不同:{prop1:number} - > {prop1:number,prop1Observable:Observable } 。基本上,你可以在没有反向映射的情况下做同样的事情吗?如果我理解正确,你不能。 –