TS官方Handbook: TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org) 基礎 相關概念 運行時錯誤:JS 的大多數錯誤都只能在運行的過程中被髮現。 靜態類型系統:TS 可以在運行代碼之前發現錯誤。 非異常失敗 ...
TS官方Handbook: TypeScript: Handbook - The TypeScript Handbook (typescriptlang.org)
基礎
相關概念
-
運行時錯誤:JS 的大多數錯誤都只能在運行的過程中被髮現。
-
靜態類型系統:TS 可以在運行代碼之前發現錯誤。
-
非異常失敗:例如在 JS 中訪問一個對象不存在的屬性,不會導致異常,而是返回
undefined
,這種情況就是非異常失敗,容易被忽略。 -
類型工具:TS 可以通過類型聲明,在訪問變數或者其它屬性的時候提供代碼補全和錯誤信息提示。
TypeScript編譯器 tsc
使用npm
全局安裝
npm install -g typescript
執行tsc demo.ts
可以將ts
文件編譯為js
文件,並及時發現錯誤,而不是等待 JS 代碼執行時。
報錯時仍產出文件
TypeScript 的核心原則:大多數時候,開發人員比 TypeScript 更瞭解代碼。
當tsc編譯過程中檢測到報錯,仍會產出js文件。
這一特性可以方便將 JS 項目遷移到 TS,原先的 JS 項目本就是可以運行的,不需要完全更改到符合 TS 的標準(工作量太大了)。
如果需要更嚴格的編譯,可以使用noEmitOnError
編譯選項。
tsc --noEmitOnError demo.ts
顯示類型與類型標註
通過冒號加類型的方式給變數標註類型。
function greet(person: string, date: Date) {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
}
擦除類型與降級
-
擦除類型: 在編譯過程中,類型標註會被擦除,因為類型標註不是 JS 的語法特性,不被瀏覽器支持,這也是使用 TS 需要使用編譯器將代碼編譯為 JS 的原因。
-
降級:TS 可以將高版本 ECMAScript的代碼重寫為低版本(ES3或者ES5)的代碼。預設降級到ES3,可以使用
target
選項指定版本轉換,例如:tsc --target es2015 demo.ts
.
雖然預設的目標代碼採用的是 ES3 語法,但現在瀏覽器大多數都已經支持 ES2015 了。
所以,大多數開發者可以安全地指定目標代碼採用 ES2015 或者是更高的 ES 版本,除非你需要著重相容某些古老的瀏覽器。
嚴格性
TS 的嚴格性是在一個區間內調節的。
可以在tsconfig.json
中通過設置strict: true
一次性開啟全部嚴格性設置。
也可以單獨開啟或者關閉某個設置,其中:
-
noImplicitAny
:當有變數被隱式地被推斷為any
時報錯。也就是說需要顯性的指定
any
(不推薦),或者隱式推斷可以推斷出具體類型,或者手動指定明確的類型(最好)。 -
strictNullCheck
:嚴格地處理null
和undefined
。
常見類型與概念
基本類型
與 JS 中一致的:string
,number
,boolean
。
數組
使用type[]
或者泛型Array<type>
。
對象
簡單的對象可以:(複雜的對象用interface
聲明)
function printCoord(pt: { x: number; y: number }) {
console.log("The coordinate's x value is " + pt.x);
console.log("The coordinate's y value is " + pt.y);
}
printCoord({ x: 3, y: 7 });
聯合類型
使用|
分隔多種允許的類型。
類型別名
使用type
聲明。
type Point = {
x: number;
y: number;
};
type ID = number | string;
介面
interface Point {
x: number;
y: number;
}
類型別名和介面之間的區別
類型別名和介面非常相似,在大多數情況下可以在它們之間自由選擇。 幾乎所有的
interface
功能都可以在type
中使用,關鍵區別在於不能重新開放類型以添加新的屬性,而介面始終是可擴展的。
類型斷言 Type Assertions
考慮到多態的情況,有時候 TS 只能推斷出父類,假如我們明確知道具體的子類,可以使用類型斷言。
如果斷言錯誤,會及時報錯。
// 使用 as 關鍵字
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
// 使用<>,這種寫法不能出現在tsx中,會被誤判
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
// 報錯
const x = "hello" as number;
文字類型 Literal Type
使用var
或let
聲明的量是變數,因此對應的類型是指定的數據類型。
而使用const
聲明的量是常量,本身就不能再改變,TS 將其值作為類型(只適用於string
和number
)。
字元串可以作為類型,於是聯合類型可以聯合多個字元串形成枚舉類型:
let alignment: "left"|"center"|"right" = "center";
使用const
聲明對象,對象的內部欄位不會被當作文字類型:
// 這裡的 obj.num 會被推斷為number類型
const obj = {num: 0};
一個較詳細的例子
const req = {url:"https://example.com", method: "GET"};
// 這裡會報錯,因為req.method是string類型,不是"GET"或"POST"類型
handleRequest(req.url, req.method);
// 函數類型聲明
function handleRequest(url:string, method:"GET"|"POST"){...}
修正方法1:使用類型斷言
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
change1意味著斷言req.method
的類型為"GET"
,這可以在類型推斷的時候將其視為"GET"
,而不是更廣泛的string
。
change2用於斷言傳入的參數的類型為"GET"
,確保沒有意料之外的錯誤。
修正方法2:使用 as const
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);
req.url
和req.method
都會變成文字類型,req.method
的類型變成"GET"
,而req.url
的類型變成了"https://example.com"
,看起來很奇怪,但是這種類型可以視作string
類型的子類型,也可以被函數匹配到。
對於null和undefined的處理
建議開啟strictNullChecks
,在傳遞值的時候手動檢查是否為null
或undefined
,或者使用!
斷言一個變數非空:
function doSomething(x: string | null) {
if (x === null) {
// do nothing
} else {
console.log("Hello, " + x.toUpperCase());
}
}
function liveDangerously(x?: number | null) {
// No error
console.log(x!.toFixed());
}