在看這篇文章之前,我是強烈推薦TypeScript 入門教程這本書的。因為這本書它是:從 JavaScript 程式員的角度總結思考,循序漸進的了解TypeScript。文章來源也是該書,但聽我一句話:踩過坑才代表會了。【建議收藏】
希望你看這本書之前已經具備了以下技能:
- 熟練使用JavaScript開發日常項目
一、什麼是TypeScript?
1、TypeScript詞解
Typed JavaScript at Any Scale。
添加了類型系統的 JavaScript,适用于任何規模的項目。
以上是官網[1]對于 TypeScript 的定義。強調了兩個重要特性:
- 類型系統
- 适用于任何規模
2、TypeScript的特性
1、類型系統
從 TypeScript 的名字就可以看出來,「類型」是其最核心的特性。
我們知道,JavaScript 是一門非常靈活的程式設計語言(弱類型):
- 沒有類型限制,一個變量可能開始是字元串,過一會兒又被指派為數字。
- 隐式轉換可以在運作中把變量類型轉來轉去。
- 基于原型的面向對象程式設計,使得原型上的屬性或方法可以在運作時被修改。
- 函數是 JavaScript 中的一等公民,可以指派給變量,也可以當作參數或傳回值。
這種靈活性就像一把雙刃劍,一方面使得 JavaScript 蓬勃發展,無所不能(App,桌面、小程式、網站、各種架構、服務端);但在另一方面卻因代碼參差不齊導緻維護成本較高。
而 TypeScript 的類型系統,在很大程度上彌補了 JavaScript 的缺點。
TypeScript 是靜态類型
類型系統按照「類型檢查的時機」來分類,可以分為動态類型和靜态類型。
動态類型是指在運作時才會進行類型檢查,這種語言的類型錯誤往往會導緻運作時錯誤。JavaScript 是一門解釋型語言,沒有編譯階段,是以它是動态類型,以下這段代碼在運作時才會報錯:
let foo = 1;
foo.split(' ');
// Uncaught TypeError: foo.split is not a function
// 運作時會報錯(foo.split 不是一個函數),造成線上 bug
靜态類型是指編譯階段就能确定每個變量的類型,這種語言的類型錯誤往往會導緻文法錯誤。TypeScript 在運作前需要先編譯為 JavaScript,而在編譯階段就會進行類型檢查,是以 TypeScript 是靜态類型,這段 TypeScript 代碼在編譯階段就會報錯了:
let foo = 1;
foo.split(' ');
// Property 'split' does not exist on type 'number'.
// 編譯時會報錯(數字沒有 split 方法),無法通過編譯
這段 TypeScript 代碼看上去和 JavaScript 沒有什麼差別。
實際上大部分 JavaScript 代碼都隻需要經過少量的修改(或者完全不用修改)就能變成 TypeScript 代碼,這得益于 TypeScript 強大的「類型推論」,即使不去手動聲明變量
foo
的類型,也能在變量初始化時自動推論出它是一個
number
類型。
完整的 TypeScript 代碼是這樣的:
let foo: number = 1;
foo.split(' ');
// Property 'split' does not exist on type 'number'.
// 編譯時會報錯(數字沒有 split 方法),無法通過編譯
TypeScript 是弱類型
類型系統按照「是否允許隐式類型轉換」來分類,可以分為強類型和弱類型。
以下這段代碼不管是在 JavaScript 中還是在 TypeScript 中都是可以正常運作的,運作時數字
1
會被隐式類型轉換為字元串
'1'
,加号
+
被識别為字元串拼接,是以列印出結果是字元串
'11'
。
console.log(1 + '1');
// 列印出字元串 '11'
TypeScript 是完全相容 JavaScript 的,它不會修改 JavaScript 運作時的特性,是以它們都是弱類型。
作為對比,Python 是強類型,以下代碼會在運作時報錯:
print(1 + '1')
# TypeError: unsupported operand type(s) for +: 'int' and 'str'
若要修複該錯誤,需要進行強制類型轉換:
print(str(1) + '1')
# 列印出字元串 '11'
JavaScript 和 TypeScript 中不管加号兩側是什麼類型,都可以通過隐式類型轉換計算出一個結果——而不是報錯——是以 JavaScript 和 TypeScript 都是弱類型。
雖然TypeScript是弱類型,但我們可以通過TypeScript提供的類型系統,以及ESLint提供的代碼檢查功能。使得TypeScript更像是一個「強類型」。
這樣的類型系統展現了 TypeScript 的核心設計理念:在完整保留 JavaScript 運作時行為的基礎上,通過引入靜态類型系統來提高代碼的可維護性,減少可能出現的 bug。
2、适用于任何規模
TypeScript 非常适用于大型項目,類型系統可以為大型項目帶來更高的可維護性,以及更少的 bug。
在中小型項目中由于有[類型推論],大部分類型都不需要手動聲明了,是以不會很大程度的降低開發效率,故部分中小企業也會選擇它。
TypeScript 還可以和 JavaScript 共存。如果你是老的JavaScript項目,你想改造成TypeScript的項目,但又代碼量太大并且項目要繼續更新。那麼你可以新的内容和檔案用TypeScript,老的不變。當閑下來時,可以逐漸将老的一個一個檔案的更新為TypeScript。
事實上,就算你從來沒學習過 TypeScript,你也可能已經在不知不覺中使用到了 TypeScript——在 VSCode 編輯器中編寫 JavaScript 時,代碼補全和接口提示等功能就是通過 TypeScript Language Service 實作的:
一些第三方庫原生支援了 TypeScript,在使用時就能獲得代碼補全了,比如 Vue 3.0:
有一些第三方庫原生不支援 TypeScript,但是可以通過安裝社群維護的類型聲明庫(比如通過運作
npm install --save-dev @types/react
來安裝 React 的類型聲明庫)來獲得代碼補全能力——不管是在 JavaScript 項目中還是在 TypeScript 中項目中都是支援的:
由此可見,TypeScript 的發展已經深入到前端社群的方方面面了,任何規模的項目都或多或少得到了 TypeScript 的支援。
3、與标準同步發展
TypeScript 的另一個重要的特性就是堅持與 ECMAScript 标準同步發展。
ECMAScript 是 JavaScript 核心文法的标準,自 2015 年起,每年都會釋出一個新版本,包含一些新的文法。
一個新的文法從提案到變成正式标準,需要經曆以下幾個階段:
- Stage 0:展示階段,僅僅是提出了讨論、想法,尚未正式提案。
- Stage 1:征求意見階段,提供抽象的 API 描述,讨論可行性,關鍵算法等。
- Stage 2:草案階段,使用正式的規範語言精确描述其文法和語義。
- Stage 3:候選人階段,文法的設計工作已完成,需要浏覽器、Node.js 等環境支援,搜集使用者的回報。
- Stage 4:定案階段,已準備好将其添加到正式的 ECMAScript 标準中。
一個文法進入到 Stage 3 階段後,TypeScript 就會實作它。一方面,讓我們可以盡早的使用到最新的文法,幫助它進入到下一個階段;另一方面,處于 Stage 3 階段的文法已經比較穩定了,基本不會有文法的變更,這使得我們能夠放心的使用它。
除了實作 ECMAScript 标準之外,TypeScript 團隊也推進了諸多文法提案,比如可選鍊操作符(
?.
)、空值合并操作符(
??
)、Throw 表達式、正則比對索引等。
3、怎麼安裝TypeScript和編輯器推薦
1、安裝 TypeScript
TypeScript 的指令行工具安裝方法如下:
npm install -g typescript
# 或者用yarn
以上指令會在全局環境下安裝
tsc
指令,安裝完成之後,我們就可以在任何地方執行
tsc
指令了。
編譯一個 TypeScript 檔案很簡單:
tsc hello.ts
我們約定使用 TypeScript 編寫的檔案以
.ts
為字尾,用 TypeScript 編寫 React 時,以
.tsx
為字尾。
2、編輯器
TypeScript 最大的優勢之一便是增強了編輯器和 IDE 的功能,包括代碼補全、接口提示、跳轉到定義、重構等。
主流的編輯器都支援 TypeScript,這裡我推薦使用 Visual Studio Code(前端開發神器)。
它是一款開源,跨終端的輕量級編輯器,内置了對 TypeScript 的支援。無需要編譯階段,寫完就能看到對不對。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-6acs5DXl-1635497989842)(<> “點選并拖拽以移動”)]
上圖寫完就報了錯誤,因為number沒有length屬性。
另外vscode本身也是用 TypeScript 編寫的。
下載下傳安裝:Visual Studio Code - Code Editing. Redefined
4、第一個案例Hello TS
我們從一個簡單的例子開始。
将以下代碼複制到
hello.ts
中:
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = 'TS';
console.log(sayHello(user));
然後執行
tsc hello.ts
這時候會生成一個編譯好的檔案
hello.js
:
function sayHello(person) {
return 'Hello, ' + person;
}
var user = 'TS';
console.log(sayHello(user));
在 TypeScript 中,我們使用
:
指定變量的類型,
:
的前後有沒有空格都可以。
上述例子中,我們用
:
指定
person
參數類型為
string
。但是編譯為 js 之後,并沒有什麼檢查的代碼被插入進來。
這是因為 TypeScript 隻會在編譯時對類型進行靜态檢查,如果發現有錯誤,編譯(ts檔案轉換成js的過程)的時候就會報錯。而在運作時,與普通的 JavaScript 檔案一樣,不會對類型進行檢查。
如果我們需要保證運作時的參數類型,還是得手動對類型進行判斷:
function sayHello(person: string) {
if (typeof person === 'string') {
return 'Hello, ' + person;
} else {
throw new Error('person is not a string');
}
}
let user = 'TS';
console.log(sayHello(user));
下面嘗試把這段代碼編譯一下:
function sayHello(person: string) {
return 'Hello, ' + person;
}
let user = [0, 1, 2];
console.log(sayHello(user));
編輯器中會提示錯誤,編譯的時候也會出錯:
但是還是生成了 js 檔案:
function sayHello(person) {
return 'Hello, ' + person;
}
var user = [0, 1, 2];
console.log(sayHello(user));
這是因為 TypeScript 編譯的時候即使報錯了,還是會生成編譯結果,我們仍然可以使用這個編譯之後的檔案。
如果要在報錯的時候終止 js 檔案的生成,可以在 中配置
tsconfig.json
即可。關于
noEmitOnError
,請參閱官方手冊(中文版)。 後面會在TypeScript基礎的原始資料類型[數值]中說明sconfig.json怎麼來的!
tsconfig.json
二、TypeScript基礎
1、原始資料類型
原始資料類型 · TypeScript
PS:空值中:
與
的差別是,
void
和
undefined
是所有類型的子類型。也就是說
null
類型的變量,可以指派給
undefined
類型的變量:(需要tsconfig.json中strict設定為false)
number
2、任意值
任意值 · TypeScript
3、類型推論
類型推論 · TypeScript
4、聯合類型
聯合類型 · TypeScript
PS:需要注意的是,一旦定義了可選屬性,那麼同一個接口内其他所有的屬性,都隻能是可選屬性的子集,否則将會報錯 !集合概念:string | number 為例,number為它的子集,string也為它的子集。
另一個版本問題:
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-dRdWMx1b-1635497989845)(<> “點選并拖拽以移動”)]
5、對象的類型—接口
對象的類型——接口 · TypeScript
6、數組的類型
數組的類型 · TypeScript
PS:疑惑? {
[index: number]: number;
length: number;
callee: Function;
}
中任意類型為number為什麼 callee可以是Function?
7、函數的類型
函數的類型 · TypeScript
8、類型斷言
類型斷言 · TypeScript
9、聲明檔案
聲明檔案 · TypeScript
10、内置對象
内置對象 · TypeScript
三、TypeScript進階
進階 · TypeScript
四、總結
咳,偷個懶,不一一列舉。還是那句話,對于TypeScript 入門教程這本書我是極其推薦的,學 TypeScript 還是得看它。除了以上的内容外,它還囊括了工程化配置說明。我以我學弟的人格擔保,看它必會!沖啊xdm!