巧用 TypeScrip(三)
建立一個數組很簡單:
const arr = [1]; 複製程式碼
此時 TypeScript 將會推斷arr
型別為number[]
:
arr.push('1');// Error 複製程式碼
當陣列元素具有其它型別時,可以通過型別註解的方式:
const arr: Array<string | number> = [1]; arr.push('1');// OK arr.push(true);// Error 複製程式碼
或者你也可以通過可選元組的方式:
const arr: [number, string?] = [1];// arr 的成員型別可以是: number, string, undefined arr.push('1');// OK arr.push(true);// Error 複製程式碼
使用元組形式,還能提供指定位置的型別檢查:
arr[0] = '1';// Error arr[1] = 1;// Error 複製程式碼
使用
通常,我們使用Promise.all
並行發出多個請求:
interface A { name: string; } interface B { age: number; } const [{ data: a }, { data: b }] = await Promise.all([ axios.get<A>('http://some.1'), axios.get<B>('http://some.2') ]) 複製程式碼
此時,TypeScript 能推出a
的型別是A
,b
的型別是B
。
現在,稍作改變:當滿足特定條件時,才發出第二個請求:
// 使用型別註解 const requestList: [Promise<AxiosResponse<A>>, Promise<AxiosResponse<B>>?] = [axios.get<A>('http://some.1')]; if (flag) { requestList[1] = (axios.get<B>('http://some.2')); }; const [ { data: a }, response ] = await Promise.all(requestList); 複製程式碼
我們期望它會如預想時那樣工作,可是事與願違,Promise.all(requestList)
,會出現型別相容性的報錯,在這個ofollow,noindex">Issues
裡,描述了相同的問題。
現在,你可以通過斷言的方式,來讓程式正常運作:
const requestList: any[]= [axios.get<A>('http://some.1')];// 設定為 any[] 型別 if (flag) { requestList[1] = (axios.get<B>('http://some.2')); } const [ { data: a }, response ] = await Promise.all(requestList) as [AxiosResponse<A>, AxiosResponse<B>?] // 型別安全 複製程式碼
字面量型別
在 JavaScript 基礎上,TypeScript 擴充套件了一系列字面量型別,用來確保型別的準確性。
如建立一個字串字面量:
const a = 'hello';// a 的型別是 'hello' a = 'world';// Error 複製程式碼
或者你也可以:
let a: 'hello' = 'hello';// a 的型別是 'hello' a = 'world';// Error 複製程式碼
其它資料型別與此相似。
你也可以定義交叉型別與聯合型別的字面量:
interface A { name: string; } interface B { name: string; age: number; } type C = A | B; type D = A & B; 複製程式碼
物件字面量型別
對於物件字面量的型別,TypeScript 有一個被稱之為 「Freshness 」的概念,它也被稱為更嚴格的物件字面量檢查,如下例子:
let someThing: { name: string }; someThing = { name: 'hello' };// ok someThine = { name: 'hello', age: 123 };// Error, 物件字面量只能指定已知屬性, { name: string } 型別中不存在 age 屬性 let otherThing = { name: 'hello', age: 123 }; someThing = otherThing;// ok 複製程式碼
TypeScript 認為建立的每個物件字面量都是 「 fresh 」 狀態;當一個 「 fresh 」 物件字面量賦值給一個變數時,如果物件的型別與變數型別不相容時,會出現報錯(如上例子中someThine = { name: 'hello', age: 123 };
的錯誤);當物件字面量的型別變寬,物件字面量的 「 fresh 」 狀態會消失(如上例子中someThing = otherThing;
,賦值以後,someThing
的型別變寬)。
一個更實際的用例如下:
function logName(something: { name: string }) { console.log(something.name); } const obj = { name: 'matt', job: 'being awesome' } logName(obj); // ok logName({ name: 'matt' }); // ok logName({ nama: 'matt' }); // Error: nama 屬性在 { name: string } 屬性中不存在。 logName({ name: 'matt', job: 'being awesome' }); // Error: 物件字面量只能指定已知屬性,`job` 屬性在這裡並不存在。 複製程式碼
基本原理與上文中相似,當想用更嚴格的型別檢查時,可以傳一個具有 fresh 狀態的物件字面量(如logName({ name: 'matt', job: 'being awesome' });
)。當你想多傳一些屬性至函式,可以將物件字面量賦值至一個新變數,然後再傳至函式(如logName(obj)
)。或者你也可以通過給函式形參新增多餘型別的方式function logName(someThing: { name: string; [key: string]: string })
。