轉(zhuǎn)發(fā) # TypeScript基礎(chǔ)入門之高級類型的索引類型(Index types)
高級類型
索引類型(Index types)
使用索引類型,編譯器就能夠檢查使用了動態(tài)屬性名的代碼远搪。 例如永毅,一個常見的JavaScript模式是從對象中選取屬性的子集。
function pluck(o, names) {
return names.map(n => o[n]);
}
下面是如何在TypeScript里使用此函數(shù)丧没,通過 索引類型查詢和 索引訪問操作符:
function pluck<T, K extends keyof T>(o:T, names: K[]): T[K][] {
return names.map(n => o[n])
}
interface Interface1 {
name: string;
age: number;
}
let i: Interface1 = {
name: "A",
age: 1,
}
let pluckStr: string[] = pluck(i, ['name'])
console.log(pluckStr)
運行后輸出如下
[ 'A' ]
編譯器會檢查 name是否真的是Interface1的一個屬性鹰椒。 本例還引入了幾個新的類型操作符。 首先是 keyof T呕童, 索引類型查詢操作符漆际。 對于任何類型 T, keyof T的結(jié)果為 T上已知的公共屬性名的聯(lián)合夺饲。 例如:
let someProps: keyof Interface1; // 'name' | 'age'
keyof Interface1是完全可以與'name'|'age'互相替換的奸汇。 不同的是如果你添加了其它的屬性到Interface1,例如address: string往声,那么 keyof Interface1會自動變?yōu)?name'|'age'|'address'擂找。 你可以在像pluck函數(shù)這類上下文里使用 keyof,因為在使用之前你并不清楚可能出現(xiàn)的屬性名浩销。 但編譯器會檢查你是否傳入了正確的屬性名給 pluck:
pluck(i, ['age', 'unknown']); // error, 'unknown' is not in 'name' | 'age'
第二個操作符是T[K]贯涎,索引訪問操作符。 在這里慢洋,類型語法反映了表達式語法塘雳。 這意味著 i['name']具有類型Interface1['name'] — 在我們的例子里則為string類型。 然而且警,就像索引類型查詢一樣粉捻,你可以在普通的上下文里使用 T[K],這正是它的強大所在斑芜。 你只要確保類型變量 K extends keyof T就可以了肩刃。 例如下面 getProperty函數(shù)的例子:
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
getProperty里的 o: T和 name: K,意味著 o[name]: T[K]杏头。 當(dāng)你返回 T[K]的結(jié)果盈包,編譯器會實例化鍵的真實類型,因此 getProperty的返回值類型會隨著你需要的屬性改變醇王。
let name: string = getProperty(i, 'name');
let age: number = getProperty(i, 'age');
let unknown = getProperty(i, 'unknown'); // error, 'unknown' is not in 'name' | 'age'
索引類型和字符串索引簽名
keyof和T[K]與字符串索引簽名進行交互呢燥。如果你有一個帶有字符串索引簽名的類型,那么 keyof T會是 string寓娩。并且T[string]為索引簽名的類型:
interface Map<T> {
[key: string]: T;
}
let keys: keyof Map<number>; // string
let value: Map<number>['foo']; // number