巧用 TypeScript(三)

數組與元組

建立一個數組很簡單:ios

const arr = [1];
複製代碼

此時 TypeScript 將會推斷 arr 類型爲 number[]git

arr.push('1');  // Error
複製代碼

當數組元素具備其它類型時,能夠經過類型註解的方式:github

const arr: Array<string | number> = [1];

arr.push('1');  // OK
arr.push(true);  // Error
複製代碼

或者你也能夠經過可選元組的方式:typescript

const arr: [number, string?] = [1];         // arr 的成員類型能夠是: number, string, undefined 
arr.push('1');   // OK
arr.push(true);   // Error
複製代碼

使用元組形式,還能提供指定位置的類型檢查:axios

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),會出現類型兼容性的報錯,在這個 Issues 裏,描述了相同的問題。ui

如今,你能夠經過斷言的方式,來讓程序正常運做:spa

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
someThing = { 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 })

更多

相關文章
相關標籤/搜索