> 本文不講如何安裝,只講代碼中的實(shí)際應(yīng)用
# 一、什么是 TypeScript?
typescript是js的超集,它在js的基礎(chǔ)上增加了靜態(tài)類型校驗(yàn),可以在運(yùn)行前校驗(yàn)js中的一些錯(cuò)誤并修正。
在定義類型之后,js中任何地方都會(huì)有文檔提示,對(duì)象中包含的值都可以提示出來,這一點(diǎn)讓js變得相當(dāng)友好。
那么想要在已有項(xiàng)目中增加ts需要怎么做?
ts支持漸進(jìn)式遷移,可配置只檢查部分文件,在已有項(xiàng)目中慢慢改造。ts的類型檢查不會(huì)影響js代碼的執(zhí)行、這意味著,即便類型校驗(yàn)有錯(cuò)誤,代碼依舊運(yùn)行良好。
ts的困難在于它需要定義所有的值類型,這個(gè)工作量還是蠻大的。
# 二、ts的簡(jiǎn)單使用
**ts的類型定義語法如下**
- 基礎(chǔ)類型:
```javascript
let isDone: Boolean = false;
let str: String = '';
let count: Number = 1;
// 使用聯(lián)合操作符
let some1: Number | String = 1;
let some2: Number | String = '1';
```
- 數(shù)組
```javascript
let arr1: number[] = [1,2];
let arr2: Array<string> = ['1','2']; // 泛型寫法,下面會(huì)講
let arr3: [string,boolean] = ['1',false]; // 元組-定義已知數(shù)量和類型
```
- 對(duì)象(當(dāng)存在復(fù)雜對(duì)象時(shí),使用接口和類來聲明,后面會(huì)講)
```javascript
let obj: {a: string, b: number } = {a: '我是字符串',b: 2};
```
- any
```javascript
let something: any = 'asd';
```
any用來表示任何類型,ts不會(huì)對(duì)它進(jìn)行校驗(yàn)。
>? 如果你的ts代碼中到處都是any,建議不要使用ts更方便些。
- viod、null、undefined、never
這些值基本沒什么用,有興趣可以自己查看[文檔](https://www.tslang.cn/docs/handbook/basic-types.html)
- 枚舉 **enum**
**enum**類型是對(duì)JavaScript標(biāo)準(zhǔn)數(shù)據(jù)類型的一個(gè)補(bǔ)充。 使用枚舉類型可以為一組數(shù)值賦予友好的名字。
```javascript
enum Color {Red, Green, Blue} // 默認(rèn)情況下,從0開始為元素編號(hào)。
let c: Color = Color.Green; // => 1
//你也可以手動(dòng)的指定成員的數(shù)值。 例如,我們將上面的例子改成從 1開始編號(hào):
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green; // => 2
```
它不但可以使用key獲取value,還可以使用value獲取key。
```javascript
enum Color {Red=1, Green, Blue}
let colorName: string = Color[2]; // => 'Green'
```
# 三、ts進(jìn)階使用
## 類型斷言
當(dāng)你確定某個(gè)值的類型時(shí),你可以指定它的類型。它有兩種寫法:
尖括號(hào)寫法
```javascript
let someValue: any = "this is a string"; // any未知類型
let str: string = someValue; // error someValue不是string類型
// 斷言為string,校驗(yàn)成功
let str: string = <string>someValue;
```
as寫法
```javascript
let someValue: any = "this is a string";
let str: string = someValue as string
```
## 接口interface
interface用來定義復(fù)雜類型(對(duì)象、函數(shù)、索引類型等)
```javascript
interface Config {
? readonly color: string; // 定義只讀
? width?: number; // 定義可選屬性
}
function doSome( option: Config ){
? // option.color
? // option.width
}
```
同一作用域中同名的interface會(huì)自動(dòng)合并
```javascript
interface Config {
? color: string;
? width: number;
}
// 同一作用域中
interface Config {
? height: number;
}
// 會(huì)合并為
interface Config {
? color: string;
? width: number;
? height: number;
}
```
extentds (interface可以使用extentds進(jìn)行拓展)
```javascript
interface Parent{
? readonly color: string; // 可定義常量
? width: number;
}
interface Children extends Parent{
? height: number;
}
```
## 類
公共,私有 與 存取
1、public
```javascript
class Animal {
? ? name: string; // 默認(rèn)為public
? ? public id: string; // 也可以標(biāo)明public
}
```
2、private
```javascript
class Animal {
? ? // private 禁止在類的外部訪問
? ? private move() {
// dosomething
? ? }
}
new Animal().move; // 錯(cuò)誤: 'move' 是私有的.
```
3、get、set
TypeScript支持通過getters/setters來截取對(duì)對(duì)象成員的訪問。與vue的watcher同理。
```javascript
class Animal {
? ? get fullName(): string {
? ? ? ? return this._fullName;
? ? }
? ? set fullName(newName: string) {
? ? ? ? // dosomething
? ? }
}
```
4、readonly標(biāo)明只讀
```javascript
class Animal {
? ? readonly number: number = 8;
}
```
還有static、protected等,這里不過多說明,詳情請(qǐng)看[文檔。](https://www.tslang.cn/docs/handbook/classes.html)
## 函數(shù)
函數(shù)類型包含兩部分:參數(shù)類型和返回值類型。
```javascript
// :number 表示返回值為number
function add(x: number, y: number): number {
? ? return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
```
聲明一個(gè)未賦值函數(shù)
```javascript
let fn: (x: number, y: number) => number;
fn = myAdd;
```
除此之外,interface同樣可以聲明函數(shù)類型
```javascript
// : boolean表示返回值為布爾值
interface Func {
? (source: string, subString: string): boolean;
}
// 命名為x,y或者其他都可以
let ff: Func = (x: string, y: string): boolean => {
return x === y
}
```
函數(shù)參數(shù)類型只會(huì)校驗(yàn)它的類型,不會(huì)校驗(yàn)它的名字
## type類型別名
類型別名會(huì)給一個(gè)類型起個(gè)新名字。它可以作用于原始值,聯(lián)合類型,元組以及其它任何你需要手寫的類型。它的語法看起來像是普通的js。
```java
// 給String重新命名
type Easing = String
// 定義聯(lián)合類型
type Easing = 'a' | 'b' | 'c'
```
type可以將多個(gè)interface聯(lián)合或者交叉
```java
interface A{
? ? kind: "square";
? ? size: number;
}
interface B{
? ? kind: "rectangle";
? ? width: number;
? ? height: number;
}
interface C{
? ? kind: "circle";
? ? radius: number;
}
type Shape1 = A | B | C; // 聯(lián)合
type Shape2 = A & B & C; // 交叉
```
type也可以聲明函數(shù)和元組
```java
// 函數(shù)
type Easing = () => string
// 元組
type DudeType = {
? [key in Keys]: string // keys是一個(gè)索引類型
}
```
> type和interface功能類似,但type更像一個(gè)值而不是一個(gè)類型。在兩者都能實(shí)現(xiàn)需求的情況下,官方建議優(yōu)先使用interface。
# 四、ts高級(jí)用法--泛型
考慮到代碼的可重用性和拓展性,ts允許使用泛型來定義未知類型,使用尖括號(hào)語法。
```javascript
// 當(dāng)入?yún)⑽粗獣r(shí),我們可定義一個(gè)泛型
function identity<T>(arg: T): T {
? ? return arg;
}
// 它可以這樣用,表示數(shù)組
function identity<T>(arg: T[]): T[] {
? ? return arg;
}
// 或者表示對(duì)象
function identity<T>(arg: {x: T, y: T}): T {
? ? return arg.x;
}
```
泛型支持extends語法
```javascript
interface Lengthwise {
? ? length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
? ? console.log(arg.length);? // 可以用時(shí)length屬性
? ? return arg;
}
```
泛型promise使用示例
```typescript
// Promise<T>表示Promise.resolve的值類型是T
// catch類型默認(rèn)是any
let ajax = <T>(params: any): Promise<T> => {
? return new Promise((resolve) => {
? ? axios.get('/list').then(res=> {
? ? ? resolve(params)
? ? })
? })
}
// 使用時(shí)
ajax<{a: string,b:number}>(params).then(res=>{
? ? // res 類型為{a: string,b:number}
)
```
>此處只講了typescript的一些常見用法和問題,更多說明請(qǐng)看官方文檔。[(中文文檔3.1](https://www.tslang.cn/docs/release-notes/typescript-3.1.html),[英文文檔4.1)](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html)
==一些運(yùn)算操作符==
1. !斷言此處有值。
```javascript
let y!:number = 1; // 表示y必定有值
```
2. ?表示可能未定義。
```javascript
let obj = {
? ? y?: number, // 相當(dāng)于? number | undefined
? ? z: string
}
let num: number;
num = obj.y; // error,不能將類型“number | undefined”分配給類型“number”。
```
3. ?? 空值合并。
通常我們?nèi)∫粋€(gè)可能存在的值時(shí),會(huì)像這樣
```javascript
let obj = {
? ? y?: number
}
let num: number;
num = obj.y || 1;
```
但當(dāng)obj.y為0時(shí),它會(huì)存在問題。所以ts提供了更好的解決方案。??只會(huì)判斷null和undefined兩個(gè)值。
```javascript
let obj = {
? ? y?: number
}
let num: number;
num = obj.y ?? 1; // 即使y為0,也會(huì)得到0,而不是1
```
4.!取值用法和?的賦值用法。
!表示必定有值,?表示可能有值,所以他們也可以這樣使用
當(dāng)你確定值必定存在時(shí)
```javascript
let obj: {
? ? a?: {
? ? ? ? ? b?: number
}
} = { a: { b: 1 } };
let x: number = obj.a.b; // 報(bào)錯(cuò),對(duì)象可能未定義
let y: number = obj!.a!.b; // 通過
```
當(dāng)你不確定值是否存在
```javascript
let obj: {
? ? ? a?: {
? ? ? ? b?: number
? ? ? }
? ? }
obj.a.b = 1; // 報(bào)錯(cuò)
obj?.a?.b = 1; // 通過
```
5. ?。ǚ旁趘alue之后)允許null和undefined
```javascript
let y:number
y = null // 無法通過編譯
y = undefined // 無法通過編譯
y = null!? ? ? // 通過
y = undefined! // 通過
```
6. 最新特性??=、||=、&&=?
有時(shí)候我們需要對(duì)可能存在的值給一個(gè)默認(rèn)值
```javascript
let obj = {
? ? y?: number
}
// 正常情況
obj.y = obj.y ? obj.y : 1;
// 使用??空值合并
obj.y = obj.y ?? 1;
// 使用??=運(yùn)算符,他看起來有點(diǎn)像 +=和-=
obj.y ??= 1;
```