剛開始學的時候,很常把這兩個英文名稱搞混XD
光看解釋,可能看不出兩者的差異,等等看範例會更清楚
廣義來說兩者都是在明確定義型別,但型別註釋主要用於型別的安全檢查和編譯時檢查,而型別斷言則是一種「逃逸機制」,可以在特定情況下覆蓋 TypeScript 的型別推斷
關於型別註釋,有興趣可以看這篇文章
🔗 Day12 - 型別註釋 & 型別推斷
本篇文章將一起來了解「Type Assertion 型別斷言
」的語法和使用時機
型別斷言就很像在告訴編譯器說:「來~相信我,這邊就聽我的,我知道我自己在做什麼」
型別斷言是告訴編譯器,在編譯期間將某個值視為另一個型別。如果斷言錯誤,是有可能在運行時造成錯誤的
使用時機:當你有十足把握確定你比 TypeScript 更清楚這裡會是哪種型別時
下面這是一段會報錯的 code
這是因為 id
若今天傳入的是 number 就無法使用字串的方法 toUpperCase()
來做轉換
function printId(id: number | string) {
console.log(id.toUpperCase());
};
這時可以透過「型別斷言
」來解決
「型別斷言」有以下兩種常見語法:
as
語法as
後如下function printId(id: number | string) {
console.log((id as string).toUpperCase());
};
原本的 id 外加了一個 ()
,並指定它是 string (valuable as string
)
<type>
角括號語法注意:在 React
<>
會和 JSX 定義元素的寫法產生衝突,所以在 React 中應使用as
關鍵字來定義型別斷言,否則會報錯唷
function printId(id: number | string) {
console.log((<string>id).toUpperCase());
};
以下的兩段英文敘述都是擷取自官方文件
Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion
這段是在說,在 TypeScript 中型別斷言(Type Assertions)只對編譯器有影響,用來告知編譯器這裡是什麼型別。然而,一旦 TypeScript 被編譯成 JavaScript 時,型別斷言都會被「移除」,因為 JavaScript 是動態型別語言,不支持在運行時直接進行型別的檢查
來看下方這個範例吧!
把 someValue
的值斷言為 string
,並調用 toUpperCase()
方法
這段 code 在 TypeScript 中是不會報錯的
let someValue: any = 123;
let upperCaseValue: string = (someValue as string).toUpperCase();
編譯成 JavaScript 後如下,型別斷言都消失了!因為數字無法調用 toUpperCase()
方法 ,所以在運行(runtime) 時就會報錯
let someValue = 123;
let upperCaseValue = someValue.toUpperCase(); // ❌
// ❌ TypeError: someValue.toUpperCase is not a function
TypeScript only allows type assertions which convert to a more specific or less specific version of a type
這段主要在說,使用型別斷言時,只允許將型別轉換為更具體(more specific)或更廣泛(less specific version)的型別,不允許將型別斷言成一個完全無關的型別,例如:不能將「string」斷言成「number」)
這段在 TypeScript 中會報錯
const x = "hello" as number;
// ❌ Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
as HTML....Element
HTMLDivElement
:用於 <div>
HTMLInputElement
:用於 <input>
HTMLAnchorElement
:用於 <a>
HTMLButtonElement
:用於 <button>
HTMLFormElement
:用於 <form>
const inputEl = document.querySelector(".test") as HTMLInputElement;
const inputEl2: HTMLInputElement = document.querySelector(".test");
Const Assertion
稱為「常數斷言」,語法是 as const
,位置通常會放在「最後面」
「常數斷言」,它用來修改型別推斷的結果,確保所有元素都被指派為 Literal Types,而不是其他型別,例如:string, number
用在變數宣告或表達式的型別上時,它會強制將變數或表達式的型別視為常數,是不可變的(immutable),只可讀取 (readonly)
const directions = ['up', 'down', 'left', 'right']
const directions2 = ['up', 'down', 'left', 'right'] as const; // 常數斷言
第一個為一般的 Arrary; 第二個為其常數斷言,兩者推斷的結果如下directions2
被推斷為 readonly ['up', 'down', 'left', 'right']
,且值是不可變的,並且每個元素的型別都是 Literal Types
這時候對一個 directions2
進行操作(如:push()),就會報錯
directions2.push('NONE');
// ❌ Property 'push' does not exist on type 'readonly ["up", "down", "left", "right"]'.
語法:const a = expr(表達式) as any as T(特定型別);
這是一個雙重斷言的語法
第一個 as
將 某段表達式 斷言為 any
第二個 as
再斷言為特定的型別 T
附上實際範例如下
1.
interface User {
id: number;
name: string;
email: string;
}
function fetchData(): any {
return {
id: 1,
name: "Hannah",
email: "hanforwork@example.com"
};
}
const expr = fetchData();
const user = expr as any as User; // 雙重斷言, ✅ Pass
function handler(e: Event) {
const element = (e as any) as HTMLElement; // 雙重斷言,✅ Pass
}
雖然使用「雙重斷言」可以解決某些煩人的型別問題,但應該被視為最後的選擇,過度依賴可能會掩蓋潛在的型別問題,降低可維護性和安全性。只有在確定無法透過其他更安全的方法解決型別問題時,才考慮使用這種方法
每天講的內容有推到 github 上喔