TS 的類型系統爲咱們的代碼提供健壯性,可維護性的保障。javascript
固然除去一些基本類型外,咱們有時也須要表達一些複雜的類型,那這個時候靈活使用一些關鍵字
就很方便了。html
這篇文章,就拿出一些能夠方便咱們進行類型表達的關鍵字來看一看。java
extends
在類型表達時,有下面兩種用法:git
interface Person { name: string; age: number; } interface Player extends Person { item: 'ball' | 'swing'; } 複製代碼
// 若是 T 能夠知足類型 Person 則返回 Person 類型,不然爲 T 類型 type IsPerson<T> = T extends Person ? Person : T; 複製代碼
在 TS 中用於類型表達時,typeof
能夠用於從一個變量上獲取它的類型。github
舉一個沒有卵用的例子:typescript
const value: number = 10; const value2: typeof vlaue = 100; // const value2: number 複製代碼
可是請注意下面這種狀況:數組
const value = 10; const value2: typeof vlaue = 100; // const value2: 10 // ERROR: Type '100' is not assignable to type '10' 複製代碼
經測試,number
string
boolean
類型在沒有聲明而直接賦值的狀況下,都會存在這個問題markdown
對於對象,數組,函數類型來說,這個仍是有點用的。參考函數
const data = { value: 123, text: 'text', subData: { value: false } }; type Data = typeof data; // type Data = { // value: number; // text: string; // subData: { // value: boolean; // }; // } 複製代碼
keyof
是TS中的索引類型查詢操做符。keyof T
會獲得由 T
上已知的公共屬性名組成的聯合類型。oop
Keyof T, the index type query operator. For any type T, keyof T is the union of known, public property names of T
舉個例子:
interface Person { name: string; age: number; phoneNum: number; } type PersonProperty = keyof Person; // type PersonProperty = "name" | "age" | "phoneNum" 複製代碼
keyof
在咱們限制類型或者枚舉屬性時仍是很是常見的,好比下面這個小例子:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
複製代碼
這樣當咱們嘗試獲取不在目標對象上的屬性值時,TS會爲咱們檢查到這樣簡單的錯誤
T[K]
在TS裏稱做索引訪問操做符(indexed access operator
)。它能夠爲咱們準確解析目標對象上的對應屬性的正確類型。
在下面的介紹,咱們能夠繼續看到 keyof
的應用。
in
操做符用於遍歷目標類型的公開屬性名。相似 for .. in
的機制。
從其用途看,咱們很容易想到 in
可用於聯合類型或者枚舉類型。
咱們能夠像下面這樣使用枚舉類型:
enum Letter { A, B, C, } type LetterMap = { [key in Letter]: string; } // type LetterMap = { // 0: string; // 1: string; // 2: string; // } 複製代碼
咱們能夠像下面這樣使用聯合類型:
type Property = 'name' | 'age' | 'phoneNum'; type PropertyObject = { [key in Property]: string; } // type PropertyObject = { // name: string; // age: string; // phoneNum: string; // } 複製代碼
利用可用於聯合類型的特性,咱們有下面這種很常見的作法(僅舉例):
type ToString<T> { [key in keyof T]: string; } 複製代碼
值得一提的是,一些基礎類型(string
, number
, symbol
)也能夠用於 in
操做符:
type StringKey = { [key in string]: any; } // type StringKey = { // [x: string]: any; // } type NumberKey = { [key in number]: any; } // type NumberKey = { // [x: number]: any; // } type SymbolKey = { [key in symbol]: any; } // 這裏和預想的不同 TODO // type SymbolKey = {} 複製代碼
關於這一點,我認爲和TS中,string
與 number
是惟二兩個能夠作 索引簽名 的類型是一致的
interface PersonArray {
[index: number]: Person;
}
interface PlainObject {
[key: string]: any;
}
複製代碼
關於 infer
操做符,這個能夠用來進行類型推測。舉個簡單的小例子:
在 TS 中,若是咱們在 generator
函數中使用了 yield
表達式,咱們就會丟失類型。好比下面這樣:
function returnSomething() { // return something; } function* task() { // 這裏的 result 在TS中是沒有拿到正確的函數返回類型的,你們能夠試一下 const result = yield returnSomething(); } 複製代碼
那爲了解決相似的問題,TS 爲咱們內置了 ReturnType
的映射類型:
function* task() { // 這裏的 result 在TS中是沒有拿到正確的函數返回類型的,你們能夠試一下 const result: ReturnType<typeof returnSomething> = yield returnSomething(); } 複製代碼
那咱們來看一下 ReturnType
是如何作的呢,其實很簡單,就是用到了 infer
:
type ReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : any;
複製代碼
infer P
中的 P
便是表示待推斷的返回值類型。
關於 infer
的更多內容,你們能夠參考這篇文章,也但願你們能夠多多支持做者
is
操做符用於TS的類型謂詞中,是實現TS類型保護的一種方式(關於什麼是類型保護)。
好比下面這種場景:
function doSometing(value: string | number) { if (typeof value === 'string') { // TS 能夠識別這個分支中 value 是 string 類型的參數(這就叫類型保護) // do something } else { // TS 能夠識別這個分支中 value 是 number 類型的參數 // do something } } 複製代碼
除去上面這種方式之外,咱們可使用TS的類型謂詞來實現:
/** * 此函數用於判斷參數 value 是否是 string 類型 * * 因爲返回類型聲明瞭類型謂詞,能夠幫助TS在代碼分支中進行類型保護(默認返回 boolean 類型是沒辦法作到的) **/ function isString(value: any): value is string { return typeof value === 'string'; } function doSometing(value: string | number) { if (isString(value)) { // TS 能夠識別這個分支中 value 是 string 類型的參數(這就叫類型保護) } else { // TS 能夠識別這個分支中 value 是 number 類型的參數 } } 複製代碼
這樣作的好處是:實現了代碼複用,實現了更好的語義化。
其實,TS 代碼中 Array.isArray
即是使用了這樣的聲明。
interface ArrayConstructor { // ... isArray(arg: any): arg is Array<any>; } 複製代碼