本文是向大家介紹TypeScript基礎(chǔ)知識(shí)及用法,幫助大家快速了解,在前端項(xiàng)目中使用這門技術(shù)。TypeScript的類型推斷跟 VS Code 的良好搭配讓代碼效率有了極大提升。靜態(tài)類型檢測,會(huì)提示一些潛在的問題,使得開發(fā)者代碼更嚴(yán)謹(jǐn),低級錯(cuò)誤早發(fā)現(xiàn)早解決。同時(shí)TypeScript類型定義使得代碼的可讀性增強(qiáng),統(tǒng)一規(guī)范,可有效降低項(xiàng)目維護(hù)成本。
1.TypeScript簡介
什么是TypeScript?
TypeScript是微軟開發(fā)的一個(gè)開源的編程語言,通過在JavaScript的基礎(chǔ)上添加靜態(tài)類型定義構(gòu)建而成。TypeScript通過TypeScript編譯器或Babel轉(zhuǎn)譯為JavaScript代碼,可運(yùn)行在任何瀏覽器,任何操作系統(tǒng)。——來自TypeScript官方
1.1 TypeScript類型系統(tǒng)
從TypeScript的名字就可以看出來,「類型」是其最核心的特性。 我們知道,JavaScript是一門非常靈活的編程語言:
它沒有類型約束,一個(gè)變量可能初始化時(shí)是字符串,過一會(huì)兒又被賦值為數(shù)字。
由于隱式類型轉(zhuǎn)換的存在,有的變量的類型很難在運(yùn)行前就確定。
基于原型的面向?qū)ο缶幊蹋沟迷蜕系膶傩曰蚍椒梢栽谶\(yùn)行時(shí)被修改。
函數(shù)可以賦值給變量,也可以當(dāng)作參數(shù)或返回值。
這種靈活性就像一把雙刃劍,一方面使得JavaScript蓬勃發(fā)展,無所不能。另一方面也使得它的代碼質(zhì)量參差不齊, 維護(hù)成本高,運(yùn)行時(shí)錯(cuò)誤多。而TypeScript的類型系統(tǒng),在很大程度上彌補(bǔ)了JavaScript的缺點(diǎn)。
1.2 TypeScript 是靜態(tài)類型
類型系統(tǒng)按照「類型檢查的時(shí)機(jī)」來分類,可以分為動(dòng)態(tài)類型和靜態(tài)類型。
動(dòng)態(tài)類型是指在運(yùn)行時(shí)才會(huì)進(jìn)行類型檢查,這種語言的類型錯(cuò)誤往往會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。JavaScript 是一門解釋型語言,沒有編譯階段,所以它是動(dòng)態(tài)類型。
靜態(tài)類型是指編譯階段就能確定每個(gè)變量的類型,這種語言的類型錯(cuò)誤往往會(huì)導(dǎo)致語法錯(cuò)誤。TypeScript 在運(yùn)行前需要先編譯為 JavaScript,而在編譯階段就會(huì)進(jìn)行類型檢查,所以 TypeScript 是靜態(tài)類型。
1.3 TypeScript 是弱類型
類型系統(tǒng)按照「是否允許隱式類型轉(zhuǎn)換」來分類,可以分為強(qiáng)類型和弱類型。
TypeScript 是完全兼容 JavaScript 的,它不會(huì)修改 JavaScript 運(yùn)行時(shí)的特性,所以它們都是弱類型。
在完整保留 JavaScript 運(yùn)行時(shí)行為的基礎(chǔ)上,通過引入靜態(tài)類型系統(tǒng)來提高代碼的可維護(hù)性,減少可能出現(xiàn)的 bug。以下這段代碼不管是在 JavaScript 中還是在 TypeScript 中都是可以正常運(yùn)行的:
console.log(1 + '1');? // 打印出字符串 '11'
1.4 適用于任何規(guī)模
TypeScript 非常適用于大型項(xiàng)目——這是顯而易見的,類型系統(tǒng)可以為大型項(xiàng)目帶來更高的可維護(hù)性,以及更少的 bug。
在中小型項(xiàng)目中推行 TypeScript 的最大障礙就是認(rèn)為使用 TypeScript 需要寫額外的代碼,降低開發(fā)效率。但事實(shí)上,由于有[類型推論][],大部分類型都不需要手動(dòng)聲明了。相反,TypeScript 增強(qiáng)了編輯器(IDE)的功能,包括代碼補(bǔ)全、接口提示、跳轉(zhuǎn)到定義、代碼重構(gòu)等,這在很大程度上提高了開發(fā)效率。而且 TypeScript 有近百個(gè)[編譯選項(xiàng)][],如果你認(rèn)為類型檢查過于嚴(yán)格,那么可以通過修改編譯選項(xiàng)來降低類型檢查的標(biāo)準(zhǔn)。
TypeScript 還可以和 JavaScript 共存。這意味著如果你有一個(gè)使用 JavaScript 開發(fā)的舊項(xiàng)目,又想使用 TypeScript 的特性,那么你不需要急著把整個(gè)項(xiàng)目都遷移到 TypeScript,你可以使用 TypeScript 編寫新文件,然后在后續(xù)更迭中逐步遷移舊文件。如果一些 JavaScript 文件的遷移成本太高,TypeScript 也提供了一個(gè)方案,可以讓你在不修改 JavaScript 文件的前提下,編寫一個(gè)[類型聲明文件][],實(shí)現(xiàn)舊項(xiàng)目的漸進(jìn)式遷移。
1.5 安裝TypeScript
TypeScript 的命令行工具安裝方法如下:
npm install -g typescript
編譯文件:
tsc hello.ts
TypeScript 最大的優(yōu)勢之一便是增強(qiáng)了編輯器和 IDE 的功能,包括代碼補(bǔ)全、接口提示、跳轉(zhuǎn)到定義、重構(gòu)等。主流的編輯器都支持 TypeScript,就連VS Code也是基于TypeScript開發(fā)的。所以VS Code對TypeScript的支持也是非常好的,強(qiáng)烈推薦大家使用起來。
2.TypeScript類型
2.1 基本類型
2.1.1 原始數(shù)據(jù)類型
原始數(shù)據(jù)類型包括布爾值boolean、數(shù)值number、字符串string、undefined、null、void。
還有ES6 中的新類型 Symbol 和 ES10 中的新類型 BigInt。(最后兩種目前運(yùn)用的比較少,暫不做介紹)
JavaScript中沒有空值(Void)的概念,在TypeScript中,可以用void表示沒有任何返回值的函數(shù)。
undefined、null、void三種的區(qū)別是,undefined和null是所有類型的子類型。也就是說undefined和null類型的變量,可以復(fù)制給所有類型的變量。而void類型的變量不能賦值給其他類型的變量。
// 1-布爾值
let isDone: boolean = false;
// 2-數(shù)值
let dogAge: number = 3;
// 3-字符串
let dogName: string = 'Strawberry';
// 4-空值
function alertName(): void {
? alert(`My dog's name is ${dogName}`);
}
// 5-undefined、null、void三種的區(qū)別
let a1: undefined = undefined;
let a2: null = null;
let a3: void;
let b1: number = undefined // ts校驗(yàn)通過
let b2: number = a2 // ts校驗(yàn)通過
let b3: number = a3 // ts報(bào)錯(cuò):不能將類型“void”分配給類型“number”。
2.1.2 any類型和unknown類型
any 和 unknown 在 TypeScript 中是所謂的“頂級類型”。
top type [...]是 通用(universal) 類型,有時(shí)也稱為 通用超類型,因?yàn)樵谌魏谓o定類型系統(tǒng)中,所有其他類型都是子類型[...]。通常,類型是包含了其相關(guān)類型系統(tǒng)中所有可能的[值]的類型。----引用自 Wikipedia:
如果一個(gè)值的類型為 any,那么我們就可以用它做任何事。任何類型的值都可以賦值給 any 類型。類型 any 也可被可賦值給每一種類型。
unknown 類型是 any 的類型安全版本。每當(dāng)你想使用 any 時(shí),應(yīng)該先試著用 unknown。在 any 允許我們做任何事的地方,unknown 的限制則大得多。在對 unknown 類型的值執(zhí)行任何操作之前,必須先通過【類型斷言】、【相等判斷】、【類型防護(hù)】、【斷言函數(shù)】進(jìn)行限定其類型,否則會(huì)ts異常(后續(xù)章節(jié)會(huì)提到)。
使用 any,我們將會(huì)失去通常由 TypeScript 的靜態(tài)類型系統(tǒng)所給予的所有保護(hù)。因此,如果我們無法使用更具體的類型或 unknown,則只能將其用作最后的手段。
// demo-1 原始類型都可以賦值給any類型的變量
let age: number = 18;
let any_word: any = 'hello';
// demo-2 在任意值上訪問任何屬性都是允許的
let anyThing: any = 'Tom';
console.log(anyThing.myName);
console.log(anyThing.myName.firstName);
// demo-3 變量如果在聲明的時(shí)候,未指定其類型,那么它會(huì)被識(shí)別為任意值類型
let something;
something = 'seven';
something = 7;
something.setName('Tom');
// demo-4 any和unknown區(qū)別
let d1: any = 0
d1.money = 100 // ts校驗(yàn)通過
let d2: unknown = 0
d2.money = 100 // ts報(bào)錯(cuò):unknown類型不存在money屬性。
2.1.3 類型推論
TypeScript 會(huì)在沒有明確的指定類型的時(shí)候推測出一個(gè)類型,這就是類型推論。
如果定義的時(shí)候沒有賦值,不管之后有沒有賦值,都會(huì)被推斷成 any 類型而完全不被類型檢查:
// demo-1 myFavoriteNumber3類型?
let myFavoriteNumber3: any = 'seven'; // 直接定義any類型
myFavoriteNumber3 = 7;
// demo-2 myFavoriteNumber4類型?
let myFavoriteNumber4; // ts推測為any類型
myFavoriteNumber4 = 'seven';
myFavoriteNumber4 = 7;
2.1.4 聯(lián)合類型
聯(lián)合類型的變量在被賦值的時(shí)候,會(huì)根據(jù)類型推論的規(guī)則推斷出一個(gè)類型:
let myFavoriteNumber5: string | number;
myFavoriteNumber5 = 'seven';
console.log(myFavoriteNumber5.length); // 5
myFavoriteNumber5 = 7;
console.log(myFavoriteNumber5.length); // ts報(bào)錯(cuò):number類型不存在length屬性
2.1.5 對象類型
聲明對象類型,經(jīng)常使用類型別名type和接口interface,二者在使用上的區(qū)別:
在類class的類型定義中我們推薦使用接口interface,因?yàn)榻涌趇nterface可以被一個(gè)類class實(shí)現(xiàn)(implements),但是類型別名type不但不能被extends和implements,就連自己也不能extends和implements其它類型。
在定義簡單類型、聯(lián)合類型、交叉類型、元組時(shí)我們用類型別名type來做,并且它和typeof能夠天然的結(jié)合在一起使用。
// 方式1-接口定義
interface Person {
? name: string;
? age: number;
}
// 方式2-類型別名定義
type Person = {
? name: string;
? age: number;
}
let tom: Person = {
? name: 'Tom',
? age: 25
};
2.1.6 數(shù)組類型
常用聲明方式:
【類型+方括號】表示方法 string[]
數(shù)組泛型 Array<T>
// demo-1 ts只允許數(shù)組中包括一種數(shù)據(jù)類型的值
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
// demo-2 如果想為數(shù)組添加不同類型的值,需要使用聯(lián)合類型
let arr3: Array<number | string> = ['aa', 2, 3] // 數(shù)組可以同時(shí)包括數(shù)值和字符串
let arr4: number[] | string[] = [1, 2, 3] // 數(shù)組只能全是數(shù)值組成,或者全字符串組成
arr4 = ['aa', 'bb']
arr4 = ['aa', 2, 3] // ts報(bào)錯(cuò):賦值類型與定義不一
2.1.7 函數(shù)類型
根據(jù)JavaScript中定義函數(shù)的2種方式:函數(shù)聲明(Function Declaration)和函數(shù)表達(dá)式(Function Expression),函數(shù)類型寫法如下:
// 1. 函數(shù)聲明(Function Declaration)
function add1(x: number, y: number): number {
? return x + y
}
add1(1, 2);
// 2. 函數(shù)表達(dá)式(Function Expression)
let add2 = (x: number, y: number): number => {
? return x + y
}
add2(1, 2);
// 可選參數(shù)必須接在必需參數(shù)后面
function add3(x: number, y?: number): void {
? console.log(x, y)
}
add3(3)
2.1.8 類型斷言
主要用于當(dāng) TypeScript 推斷出來類型并不滿足當(dāng)前需求時(shí),TypeScript 允許開發(fā)者覆蓋它的推斷,可以用來手動(dòng)指定一個(gè)值的類型。類型斷言是一個(gè)編譯時(shí)語法,不涉及運(yùn)行時(shí)。
類型斷言的常見用途有以下幾種:
聯(lián)合類型可以被斷言為其中一個(gè)類型
父類可以被斷言為子類
任何類型都可以被斷言為 any
any 可以被斷言為任何類型
要使得 A 能夠被斷言為 B,只需要 A 兼容 B 或 B 兼容 A 即可
聯(lián)合類型可以被斷言為其中一個(gè)類型,類型斷言只能夠欺騙 TS 編譯器,無法避免運(yùn)行時(shí)的錯(cuò)誤,反而濫用類型斷言可能會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。
interface Cat {
? name: string;
? run(): void;
}
interface Fish {
? name: string;
? swim(): void;
}
function swim(animal: Cat | Fish) {
? (animal as Fish).swim(); // 類型斷言,ts校驗(yàn)通過
}
const tom: Cat = {
? name: 'Tom',
? run() { console.log('run') }
};
swim(tom);
// 編譯時(shí)不會(huì)報(bào)錯(cuò),但在運(yùn)行時(shí)會(huì)報(bào)錯(cuò) Uncaught TypeError: animal.swim is not a function`
類型斷言不是類型轉(zhuǎn)換,它不會(huì)真的影響到變量的類型。
// 類型斷言
function toBoolean1(something: any): boolean {
? return something as boolean;
}
toBoolean1(1); // 返回值為 1
// 類型轉(zhuǎn)換
function toBoolean2(something: any): boolean {
? return Boolean(something);
}
toBoolean2(1); // 返回值為 true
2.1.9 聲明文件
當(dāng)使用第三方庫時(shí),我們需要引用它的聲明文件,才能獲得對應(yīng)的代碼補(bǔ)全、接口提示等功能。
聲明文件必需以 .d.ts 為后綴,聲明文件示例:
// src/jQuery.d.ts
declare var jQuery: (selector: string) => any;
推薦使用 @types 統(tǒng)一管理第三方庫的聲明文件。@types 的使用方式很簡單,直接用 npm 安裝對應(yīng)的聲明模塊即可,以 jQuery 舉例: npm install @types/jquery --save-dev
可以通過以下鏈接搜索需要的聲明文件。
https://www.typescriptlang.org/dt/search?search=
如果第三方庫沒有提供聲明文件,我們就需要自己書寫聲明文件。如何書寫聲明文件?此處略過,感興趣的話可以后期嘗試。
2.1.10 內(nèi)置對象
1.ECMAScript 標(biāo)準(zhǔn)提供的內(nèi)置對象有:
Boolean、Error、Date、RegExp 等。
更多的內(nèi)置對象,可以查看 MDN 的文檔。
2.DOM 和 BOM 提供的內(nèi)置對象有:
Document、HTMLElement、Event、NodeList 等。
而他們的定義文件,則在 TypeScript 核心庫的定義文件中。
3.TypeScript 核心庫的定義文件中定義了所有瀏覽器環(huán)境需要用到的類型,并且是預(yù)置在 TypeScript 中的。
注意,TypeScript 核心庫的定義中不包含 Node.js 部分。
4.用 TypeScript 寫 Node.js
Node.js 不是內(nèi)置對象的一部分,如果想用 TypeScript 寫 Node.js,則需要引入第三方聲明文件:
npm install @types/node --save-dev
2.2 高級類型
2.2.1 Type類型別名
類型別名就是給類型起一個(gè)新名字。用法類似于接口interface,類型別名常用于原始類型、聯(lián)合類型,元祖類型等其他必須手動(dòng)編寫的類型,示例:
interface Cat {
? name: string;
? run(): void;
}
interface Fish {
? name: string;
? swim(): void;
}
type Animal = Cat | Fish;
2.2.2 字面量類型
字符串字面量類型用來約束取值只能是某幾個(gè)字符串中的一個(gè)。
// 也可以直接使用字面量進(jìn)行類型聲明
// a只能被賦值為10 不能被賦值為其他值 類似常量 很少使用
let a: 10;
a = 10;
// 字面量形式一般用于或的形式較多
// 可以使用 | 來連接多個(gè)類型(類似聯(lián)合類型)
let b: "male" | "female";
b = "male";
b = "female";
2.2.3 元祖
數(shù)組合并了相同類型的對象,而元組(Tuple)合并了不同類型的對象。
元組起源于函數(shù)編程語言(如 F#),這些語言中會(huì)頻繁使用元組。
// 定義一對值分別為 string 和 number 的元組
let Jerry: [string, number] = ['Jerry', 18];
// 當(dāng)添加越界的元素時(shí),它的類型會(huì)被限制為元組中每個(gè)類型的聯(lián)合類型
Jerry.push('male'); // ts校驗(yàn)通過
Jerry.push(true); // ts報(bào)錯(cuò):true和"string|number"類型不匹配
2.2.4 枚舉
// demo-1 簡單枚舉:枚舉成員會(huì)被賦值為從 0 開始遞增的數(shù)字,同時(shí)也會(huì)對枚舉值到枚舉名進(jìn)行反向映射
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat };
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Tue"] === 2); // true
console.log(Days["Sat"] === 6); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
console.log(Days[6] === "Sat"); // true
// demo-2 手動(dòng)賦值:未手動(dòng)賦值的枚舉項(xiàng)會(huì)接著上一個(gè)枚舉項(xiàng)遞增,需要避免覆蓋
enum DaysNew { Sun = 7, Mon = 1, Tue, Wed, Thu, Fri, Sat };
console.log(DaysNew["Sun"] === 7); // true
console.log(DaysNew["Mon"] === 1); // true
console.log(DaysNew["Tue"] === 2); // true
console.log(DaysNew["Sat"] === 6); // true
2.2.5 類
TypeScript 可以使用三種訪問修飾符(Access Modifiers),分別是 public、private 和 protected。
public 修飾的屬性或方法是公有的,可以在任何地方被訪問到,默認(rèn)所有的屬性和方法都是 public 的
private 修飾的屬性或方法是私有的,不能在聲明它的類的外部訪問
protected 修飾的屬性或方法是受保護(hù)的,它和 private 類似,區(qū)別是它在子類中也是允許被訪問的
給類加上 TypeScript 的類型很簡單,與接口類似:
class Animal {
? public name: string; // 思考1:此處改為private后運(yùn)行結(jié)果?
? public constructor(name: string) {
? ? this.name = name;
? }
? public sayHi(): string { // 思考2:此處改為private后運(yùn)行結(jié)果?
? ? return `My name is ${this.name}`;
? }
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
「構(gòu)造函數(shù)」前加修飾符的區(qū)別:
當(dāng)構(gòu)造函數(shù)修飾為 private 時(shí),該類不允許被繼承或者實(shí)例化
當(dāng)構(gòu)造函數(shù)修飾為 protected 時(shí),該類只允許被繼承
2.2.6 類與接口
interface Alarm {
? alert(): void;
}
interface Light {
? lightOn(): void;
? lightOff(): void;
}
// demo-1 接口繼承接口
interface LightableAlarm extends Light {
? lightOn(): void;
? lightOff(): void;
}
// demo-2 類繼承接口
class Car implements Alarm, Light {
? alert() {
? ? console.log('Car alert');
? }
? lightOn() {
? ? console.log('Car light on');
? }
? lightOff() {
? ? console.log('Car light off');
? }
}
// demo-3 接口繼承類
interface LittleCar extends Car {
? console(): void;
}
let car1: LittleCar = {
? alert() {
? ? console.log('Little Car alert');
? },
? lightOn: function (): void {
? ? console.log('Little Car light on');
? },
? lightOff: function (): void {
? ? console.log('Little Car light off');
? },
? console: function (): void {
? ? console.log('Little Car');
? },
}
2.2.7 泛型
泛型(Generics)是指在定義函數(shù)、接口或類的時(shí)候,不預(yù)先指定具體的類型,而在使用的時(shí)候再指定類型的一種特性。
示例:Array<any> 允許數(shù)組的每一項(xiàng)都為任意類型。但是我們預(yù)期的是,數(shù)組中每一項(xiàng)都應(yīng)該是輸入的 value 的類型。
function createArray<T>(length: number, value: T): Array<T> {
? let result: T[] = [];
? for (let i = 0; i < length; i++) {
? ? result[i] = value;
? }
? return result;
}
2.2.8 聲明合并
如果定義了兩個(gè)相同名字的函數(shù)、接口或類,那么它們會(huì)合并成一個(gè)類型。
合并的屬性的類型必須是唯一的,如果出現(xiàn)重復(fù),類型不一致會(huì)報(bào)錯(cuò)。
interface Alarm {
? price: number;
}
interface Alarm {
? weight: number;
}
// 合并后
interface Alarm {
? price: number;
? weight: number;
}
interface Alarm {
? price: string;? // ts報(bào)錯(cuò):類型不一致
? weight: number;
}
3.實(shí)戰(zhàn):案例分享
3.1 定義提示
鼠標(biāo)放上UserInfo都會(huì)有相應(yīng)的定義提示
3.2 定義跳轉(zhuǎn)
在其他頁面運(yùn)用到UserInfo定義時(shí),鼠標(biāo)放上能快速看到定義類型和注釋,點(diǎn)擊能直接跳轉(zhuǎn)定義代碼
3.3 代碼靜態(tài)檢測
根據(jù)ts定義自動(dòng)檢測代碼,發(fā)現(xiàn)錯(cuò)誤實(shí)時(shí)提示,鼠標(biāo)放上會(huì)給出詳細(xì)信息,并提供快速修復(fù)功能。
例如:截圖中username沒有用駝峰式書寫,跟原定義不一致。點(diǎn)擊即可自動(dòng)修復(fù)。
3.4 接口定義快速引入項(xiàng)目
推薦安裝yapi-to-typescript 插件,快速自動(dòng)化獲取 YApi 或 Swagger 的接口定義,生成 TypeScript 或 JavaScript 的接口類型及其請求函數(shù)代碼。
插件安裝方法:
npm i yapi-to-typescript
生成定義代碼命令:
npx ytt
導(dǎo)出模塊接口定義步驟:
1.categories中id獲取方式:打開yapi項(xiàng)目 --> 點(diǎn)開分類 --> 復(fù)制瀏覽器地址欄 /api/cat_ 后面的數(shù)字。
2.yapi上查看項(xiàng)目token方法:
3.ytt.config.ts配置文件參考:
import { defineConfig } from 'yapi-to-typescript';
/* yapi獲取ts定義 */
export default defineConfig([
? {
? ? serverUrl: 'http://XX.XX.XX.XX:XX', // yapi項(xiàng)目地址
? ? typesOnly: true, // 只生產(chǎn)ts定義
? ? target: 'typescript',
? ? reactHooks: {
? ? ? enabled: false,
? ? },
? ? prodEnvName: 'production',
? ? outputFilePath: 'api/index.ts', // 定義輸出目錄
? ? requestFunctionFilePath: 'api/request.ts',
? ? dataKey: 'data',
? ? projects: [
? ? ? {
? ? ? ? // yapi項(xiàng)目token,存在有效期限制
? ? ? ? token: 'XXXXXXXXXXXXxx',
? ? ? ? categories: [
? ? ? ? ? {
? ? ? ? ? ? id: 123, // 獲取方式:打開項(xiàng)目 --> 點(diǎn)開分類 --> 復(fù)制瀏覽器地址欄 /api/cat_123后面的數(shù)字
? ? ? ? ? ? getRequestFunctionName(interfaceInfo, changeCase) {
? ? ? ? ? ? ? return changeCase.camelCase(interfaceInfo.parsedPath.name);
? ? ? ? ? ? },
? ? ? ? ? },
? ? ? ? ],
? ? ? },
? ? ],
? },
]);
4.自動(dòng)生成定義截圖:
4.參考文獻(xiàn)
官方手冊:https://www.typescriptlang.org/docs/handbook/basic-types.html
入門教程:http://ts.xcatliu.com/introduction/what-is-typescript.html