TypeScript 類型注解、類型推斷和類型斷言


一、類型注解(Type annotation)

所謂類型注解,就是人為為一個變量指定類型,例如:

const a: number = 123;

在 vscode 中鼠標移入 a 出現提示,冒號后面就是類型注解:

當不添加類型注解時,TypesScript 也能知道變量 a 是一個數字,這就是 TypeScript 的類型推斷:

 

二、類型推斷(Type inference)

所謂類型推斷就是 TypeScript 可以通過變量值倒推變量類型,因此在絕大部分情況下,我們是不需要去寫類型注解的

但有些情況類型推斷是無法推斷變量類型的,例如函數的參數:

function getSum(a, b) {
  return a + b;
}
const num = getSum(1, 2);

上面代碼中的參數 a,b 就無法類型:

從而也導致了 num 的類型不能判斷:

這時就需要類型注解來為參數指定類型:

function getSum(a: number, b: number) {
  return a + b;
}
const num = getSum(1, 2);

這樣 num 就可以推斷出類型了:

 

三、類型斷言(Type Assertion)

TypeScript 允許你覆蓋它的推斷,以你想要的方式分析它並手動的指定一個值的類型,這種機制被稱為類型斷言

類型斷言用來告訴編譯器你比它更了解這個類型,並且它不應該再發出錯誤

常見用例:

const foo = {};
foo.bar = 123;     // Error: 'bar' 屬性不存在於 ‘{}’
foo.bas = 'hello';  // Error: 'bas' 屬性不存在於 '{}'

這里報錯是因為 foo 的類型推斷為 {}(即具有零屬性的對象)

因此,無法在它的屬性上添加 bar 或 bas,這時就可以通過類型斷言來解決:

interface Foo {
  bar: number;
  bas: string;
}

const foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';

 

1、as foo 與 <foo>

最初的斷言語法如下:

let foo: any;
let bar = <string>foo;  // 現在 bar 的類型是 'string'

然而,當你在 JSX 中使用 <foo> 的斷言語法時,會與 JSX 的語法存在歧義:

let foo = <string>bar;</string>;

因此,為了一致性,建議使用 as foo 的語法來為類型斷言

 

2、類型斷言與類型轉換

之所以不被稱為「類型轉換」,是因為轉換通常意味着某種運行時的支持

但類型斷言純粹是一個編譯時語法,同時也是一種為編譯器提供關於如何分析代碼的方法

 

3、類型斷言被認為是有害的

大部分情況下,斷言能讓你更容易的從遺留項目中遷移

然而,如果沒有按約定添加屬性,TypeScript 編譯器並不會對以下情況發出錯誤警告:

interface Foo {
  bar: number;
  bas: string;
}

const foo = {} as Foo;

// 忘記添加上面例子的屬性

另一個常見的用法是使用類型斷言來提供代碼的提示:

interface Foo {
  bar: number;
  bas: string;
}

const foo = <Foo>{
  // 編譯器將會提供關於 Foo 屬性的代碼提示
  // 但是開發人員也很容易忘記添加所有的屬性
  // 同樣,如果 Foo 被重構,這段代碼也可能被破壞(例如,一個新的屬性被添加)。
};

這也會存在一個同樣的問題,如果忘記了某個屬性,編譯器也不會報錯

使用一種更好的方式:

interface Foo {
  bar: number;
  bas: string;
}

const foo: Foo = {
  // 編譯器將會提供 Foo 屬性的代碼提示
};

當需要創建一個臨時變量時,一般不會使用斷言,而是依靠類型推斷來檢查代碼

 

4、雙重斷言

當使用者了解傳入參數更具體的類型時,類型斷言能按預期工作:

function handler(event: Event) {
  const mouseEvent = event as MouseEvent;
}

然而,下面例子中的代碼將會報錯,盡管使用者已經使用了類型斷言:

function handler(event: Event) {
  const element = event as HTMLElement; // Error: 'Event' 和 'HTMLElement' 中的任何一個都不能賦值給另外一個
}

如果仍想使用那個類型,可以使用雙重斷言

先斷言成兼容所有類型的 any,再斷言成想使用的類型:

function handler(event: Event) {
  const element = (event as any) as HTMLElement; // ok
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM