一、類型注解(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 }