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