前言
TypeScript 的官方文件早已更新,但我能找到的中文文件都還停留在比較老的版本。所以對其中新增以及修訂較多的一些章節進行了翻譯整理。
本篇整理自 TypeScript Handbook 中 「Indexed Access Types」 章節。
本文並不嚴格按照原文翻譯,對部分內容也做了解釋補充。
正文
我們可以使用索引訪問型別(indexed access type)查詢另外一個型別上的特定屬性:
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
// type Age = number
因為索引名本身就是一個型別,所以我們也可以使用聯合、keyof
或者其他型別:
type I1 = Person["age" | "name"];
// type I1 = string | number
type I2 = Person[keyof Person];
// type I2 = string | number | boolean
type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName];
// type I3 = string | boolean
如果你嘗試查詢一個不存在的屬性,TypeScript 會報錯:
type I1 = Person["alve"];
// Property 'alve' does not exist on type 'Person'.
接下來是另外一個示例,我們使用 number
來獲取陣列元素的型別。結合 typeof
可以方便的捕獲陣列字面量的元素型別:
const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];
type Person = typeof MyArray[number];
// type Person = {
// name: string;
// age: number;
// }
type Age = typeof MyArray[number]["age"];
// type Age = number
// Or
type Age2 = Person["age"];
// type Age2 = number
作為索引的只能是型別,這意味著你不能使用 const
建立一個變數引用:
const key = "age";
type Age = Person[key];
// Type 'key' cannot be used as an index type.
// 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?
然而你可以使用型別別名實現類似的重構:
type key = "age";
type Age = Person[key];
最後講一個實戰案例:
假設有這樣一個業務場景,一個頁面要用在不同的 APP 裡,比如淘寶、天貓、支付寶,根據所在 APP 的不同,呼叫的底層 API 會不同,我們可能會這樣寫:
const APP = ['TaoBao', 'Tmall', 'Alipay'];
function getPhoto(app: string) {
// ...
}
getPhoto('TaoBao'); // ok
getPhoto('whatever'); // ok
如果我們僅僅是對 app 約束為 string
型別,即使傳入其他的字串,也不會導致報錯,我們可以使用字面量聯合型別約束一下:
const APP = ['TaoBao', 'Tmall', 'Alipay'];
type app = 'TaoBao' | 'Tmall' | 'Alipay';
function getPhoto(app: app) {
// ...
}
getPhoto('TaoBao'); // ok
getPhoto('whatever'); // not ok
但寫兩遍又有些冗餘,我們怎麼根據一個陣列獲取它的所有值的字串聯合型別呢?我們就可以結合上一篇的 typeof
和本節的內容實現:
const APP = ['TaoBao', 'Tmall', 'Alipay'] as const;
type app = typeof APP[number];
// type app = "TaoBao" | "Tmall" | "Alipay"
function getPhoto(app: app) {
// ...
}
getPhoto('TaoBao'); // ok
getPhoto('whatever'); // not ok
我們來一步步解析:
首先是使用 as const
將陣列變為 readonly
的元組型別:
const APP = ['TaoBao', 'Tmall', 'Alipay'] as const;
// const APP: readonly ["TaoBao", "Tmall", "Alipay"]
但此時 APP
還是一個值,我們通過 typeof
獲取 APP
的型別:
type typeOfAPP = typeof APP;
// type typeOfAPP = readonly ["TaoBao", "Tmall", "Alipay"]
最後在通過索引訪問型別,獲取字串聯合型別:
type app = typeof APP[number];
// type app = "TaoBao" | "Tmall" | "Alipay"
TypeScript 系列
- TypeScript 之 Narrowing
- TypeScript 之 More on Functions
- TypeScript 之 Object Type
- TypeScript 之 Generics
- TypeScript 之 Keyof Type Operator
- TypeScript 之 Typeof Type Operator
微信:「mqyqingfeng」,加我進冴羽唯一的讀者群。
如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者有所啟發,歡迎 star,對作者也是一種鼓勵。