2017-06-02 83 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 } 。基本上,你可以在沒有反向映射的情況下做同樣的事情嗎?如果我理解正確,你不能。 –