1. 程式人生 > 其它 >TypeScript學習記錄整理(待繼續完善)

TypeScript學習記錄整理(待繼續完善)

typescript

Interface

對物件的形狀進行描述

interface Person {
    name: String
    //可選屬性
    age?: number
    //只讀屬性
    readonly id: number
}

也可以用來描述函式型別

interface Random  {
    (x:number, y:number):number 
}

const add:Random =(num1,num2)=>{
    return num1+num2
}

自定義屬性

interface Key {
    [propName: string]:string
}
//看起來像類陣列
interface LikeArray {
    [propName: number]:string
}

封裝,繼承,多型

//封裝
class Person {
    //屬性
    name: string
    //構造器
    constructor(name: string) {
        this.name = name
    }
    //方法
    speak() {
        pass
    }
}
//例項化
const p1 = new Person()
//使用
p1.name
p1.speak()
//繼承 extends
class Student extends Person {
    study() {
        c.log(`${this.name} needs study`)
    }
}
const s1 = new Student('lin)

s1.study

//Student類如果還有自己定義的自己的屬性,就需要super關鍵字
class Student extends Person {
    grade: number
    constructor(name:string,grade:number) {
        super(name)
        this.grade = grade
    }
    study() {
        c.log(`${this.name} needs study`)
    }
}
//多型-子類重寫父類方法
class Student extends Person {
    speak() {
        pass
    }
}

public,private,protected,static

  • public-共有,預設是public,類例項,子類等都可以使用
  • private-只屬於類自己,其例項和其子類都不可訪問
  • protected-例項不可訪問,其子類繼承可訪問
  • static-可理解為類上的常量,類本身可以訪問,例項和子類不能訪問

抽象類-abstract-只能被繼承,不能被例項化的類

  • 不允許被例項化
  • 類中的抽象方法必須被子類實現

this型別

  • 類的成員方法直接返回this,可以實現方法鏈式呼叫
class StudyStep {
  step1() {
    console.log('listen')
    return this
  }
  step2() {
    console.log('write')
    return this
  }
}

const s = new StudyStep()

s.step1().step2() 
  • 子類成員方法返回this,可實現父類子類方法靈活呼叫
class StudyStep {
  step1() {
    console.log('listen')
    return this
  }
  step2() {
    console.log('write')
    return this
  }
}

class MyStudyStep extends StudyStep {
  next() {
    console.log('before done, study next!')
    return this   
  }
}

const m = new MyStudyStep()

m.step1().next().step2().next()  // 父型別和子型別上的方法都可隨意呼叫

interface和類的關係

interface不僅可以對物件的形狀進行描述,也可以來約束class

implements-定義約束後,class必須滿足介面上的所有條件,用於約束類例項上的屬性和方法

interface MusicInterface {
    playMusic(): void
}

class Car implements MusicInterface {
    //implements了interface後必須要滿足條件
    playMusic() {}
}

class Cellphone implements MusicInterface {
    playMusic() {}
}

約束建構函式和靜態屬性

interface CircleStatic {
    new (radius: number): void
    pi: number
}

const Circle:CircleStatic = class Circle {
    //pi在CilcleStatic中有定義,要定義為靜態屬性
    static pi: 3.14
    public radius: number
    //radius在interface中型別為number,constructor入參型別不對會報錯
    public constructor(radius: number) {
        this.radius = radius
    }
}

列舉-enum

數字遞增 & 反向對映

//數字遞增
enum Direction {
    //預設
    Up,
    //1.Up = 6
    Down,
    Left,
    Right
}
console.log(Direction.Up) //0 其餘123遞增
> 1的情況: 數字遞增從6開始,也可以每個元素都設定初始值

//反向對映
console.log(Direction[0]) //'Up'
console.log(Direction[6]) //'Up'

//原始碼解析-被編譯後的程式碼
var Direction;
(function (Direction) {
    //js中的賦值運算子返回被賦予的值
    //所以下面Direction['Up'] = 6 返回的6
    //相當於執行 Direction[6] = 'Up'
    Direction[Direction["Up"] = 6] = "Up";
    Direction[Direction["Down"] = 7] = "Down";
    Direction[Direction["Left"] = 8] = "Left";
    Direction[Direction["Right"] = 9] = "Right";
})(Direction || (Direction = {}));

計算成員

enum FileAccess {
    Read    = 1 << 1,
    Write   = 1 << 2,
    ReadWrite  = Read | Write,
}

console.log(FileAccess.Read)       // 2   -> 010
console.log(FileAccess.Write)      // 4   -> 100
console.log(FileAccess.ReadWrite)  // 6   -> 110

字串列舉

常量列舉

  • const 編譯出來的js程式碼會更簡潔,提高效能
  • 常量列舉不允許包含計算成員

型別

1.型別推論

  • 定義時不賦值會被推斷為any型,之後隨便賦值都不會報錯
let aaa
a = 22
a = 'lin'
  • 初始化變數,定義時賦值但沒指定型別
let b = 'sss'
b = 22 //報錯,初始化自動推導為string型別,賦值為number型別會報錯
  • 函式預設形參
function func(a = 22) {
    console.log(a)
    return a
}
func('saa') //自動推導為number,傳了string會報錯
  • 函式返回值
    • 無return自動推導為void
    • 有return比如上面的例子,會自動推導為number,如果給func寫了型別比如說string會報錯

2.內建型別

  • 八種基本型別
    • string number boolean null undefined object bigint symbol
  • ecmascript內建物件
    • Array Date Error RegExp等
    const nums: Arrat<number> = [1,2,3]
    const nums: number[] =[1,2,3]
    
  • DOM 和 BOM
    • HTMLElement NodeList MouseEvent等

3.聯合型別 |

希望一個變數可以支援多種型別

let num: number | string

4.交叉型別 &

物件形狀進行擴充套件,使用&

interface Person {
    name: string,
    age: number,
}
//Student在Person 有name和age屬性的基礎上還想要有grade屬性,和繼承類似
type Student = Person & {grade: number}
const s1:Student
s1.name/age/grade

5.類型別名

type Name = string                              // 基本型別

type arrItem = number | string                  // 聯合型別

const arr: arrItem[] = [1,'2', 3]

type Person = { 
  name: Name 
}

type Student = Person & { grade: number  }       // 交叉型別

type Teacher = Person & { major: string  } 

type StudentAndTeacherList = [Student, Teacher]  // 元組型別

const list:StudentAndTeacherList = [
  { name: 'lin', grade: 100 }, 
  { name: 'liu', major: 'Chinese' }
]

type和interface區別

  • 共同點: 都可以定義一個物件或函式,都允許繼承,interface使用extends實現繼承,type使用交叉型別實現繼承
  • 不同點:
    • 設計目的不同,interface是為了對物件的形狀進行描述,type是類型別名,為了讓ts寫起來更清晰
    • type可以宣告基本型別,聯合型別,交叉型別,元組,interface不行
    • interface可以合併重複宣告,type不可以,會報錯

6.型別保護

//返回入參是聯合型別的length,但是number沒有會報錯,所以用typeof處理
function getLength(arg: number | string): number {
    if(typeof arg === 'string') {
        return arg.length
    } else {
        return arg.toString().length
    }
}

7.型別斷言 as

值 as 型別

8.字面量型別

type ButtonSize = 'mini' | 'small' | 'normal' | 'large'
type Sex = '男' | '女'

泛型

解決輸入輸出要一致的問題

泛型基本使用

  • 處理函式引數
//使用<T>,相當於佔位符,在使用時定義的型別*會像引數一樣傳入*,它會原封不動地輸出
function print<T>(arg:T):T {
    console.log(arg)
    return arg
}
//使用時可以靠自己直接定義好T或者靠型別推斷
eg:
print<string>('ddd')
print('aaa')
  • 預設引數
//預設就是number型別了
interface Iprint<T = number> {
    (arg: T):T
}
  • 處理多個函式引數
//傳入一個只有兩個元素的元組,交換元組位置後返回
function swap<T, U>(tuple: [T, U]): [U, T]{
    return [tuple[1], tuple[0]]
}
  • 函式副作用操作
//根據不同的url請求返回不同型別的資料
interface UserInfo {
    name: string
    age: number
}

function request<T>(url:string): Promise<T> {
    return fetch(url).then(res => res.json())
}

request<UserInfo>('user/info').then(res =>{
    console.log(res)
})

約束泛型

和interface結合類約束泛型

interface ILength {
    length: number
}

function printLength<T extends ILength>(arg: T): T {
    console.log(arg.length)
    return arg
}
//使用
const str = printLength('Lin')
const arr = printLength([1,2,3])
const obj = printLength({length: 10})
//這個也驗證了interface的duck typing,只要你有length屬性,都符合約束,那不管你是什麼,都沒問題

泛型應用

可以在定義函式,介面或者類的時候,不預先指定具體型別,等到使用的時候再指定

  • 泛型約束類
class Stack<T> {
    private data: T[] = []
    push(item:T) {
        return this.data.push(item)
    }
    pop():T | undefined {
        return this.data.pop()
    }
}
//入棧出棧都是同一種類型
const s1 = new Stack<number>()
const s2 = new Stack<string>()
//注意,泛型無法約束類的靜態成員,給pop方法定義static關鍵字,會報錯
  • 泛型約束介面
interface IKeyValue<T, U> {
    key: T
    value: U
}

const k1:IKeyValue<number, string> = { key: 18, value: 'lin'}
const k2:IKeyValue<string, number> = { key: 'lin', value: 18}
  • 泛型定義陣列
const arr: number[] = [1,2,3]
const arr: Array<number> = [1,2,3]

索引型別

從物件中抽取指定的屬性的值拼接成陣列

const userInfo = {
  name: 'lin',
  age: '18',
}

function getValues(userInfo: any, keys: string[]) {
  return keys.map(key => userInfo[key])
}

// 抽取指定屬性的值
console.log(getValues(userInfo, ['name','age']))  // ['lin', '18']
// 抽取obj中沒有的屬性:
console.log(getValues(userInfo, ['sex','outlook']))  // [undefined, undefined]

物件中沒有sex和outlook屬性,但是ts編譯器也沒有報錯,要解決這個問題,需要對這種情況做型別約束,實現動態屬性的檢查

keyof(索引查詢)

keyof可以用於獲取某種型別的所有鍵,其返回型別是聯合型別
interface IPerson {
  name: string;
  age: number;
}

type Test = keyof IPerson; // 'name' | 'age'

T[K](索引訪問)

T[K]-表示介面T的屬性K所代表的型別
interface IPerson {
  name: string;
  age: number;
}

let type1:  IPerson['name'] // string
let type2:  IPerson['age']  // number

extends(泛型約束)

泛型變數通過extends繼承某個型別,獲得某些屬性
interface ILength {
    length: number
}

function printLength<T extends ILength>(arg: T): T {
    console.log(arg.length)
    return arg
}
const str = printLength('lin')
const arr = printLength([1,2,3])
const obj = printLength({ length: 10 })

const num = printLength(10) // 報錯,Argument of type 'number' is not assignable to parameter of type 'ILength'

檢查動態屬性

  • 定義泛型 T、K,用於約束 userInfo 和 keys
  • 為 K 增加一個泛型約束,使 K 繼承 userInfo 的所有屬性的聯合型別, 即K extends keyof T
function getValues<T, K extends keyof T>(userInfo: T, keys: K[]): T[K][] {
    return keys.map(key => userInfo[key])
}

對映型別

將一個型別對映成另一個型別

in操作符,對聯合型別實現遍歷
Partial,Partial可將T所有屬性對映為可選的

interface IPerson {
    name: string
    age: number
}

type IPartial = Partial<IPerson>
//之前初始化的時候name和age都必須要傳
let p1: IPartial = {}
  • 實現原理: 通過inkeyof
    • [p in keyof T] 遍歷T上所有的屬性
    • ?: 設定為屬性為可選的
    • T[P] 設定型別為原來的型別
type Partial<T> = {
    [P in keyof T]?: T[P]
}

Readonly-Readonly將T的所有屬性都對映為只讀

interface IPerson {
  name: string
  age: number
}

type IReadOnly = Readonly<IPerson>

let p1: IReadOnly = {
  name: 'lin',
  age: 18
}
  • 實現原理:和Partial幾乎一樣
type Readonly<T> ={ 
    readonly [P in keyof T]: T[P]
}

pick-抽取物件子集,挑選一組屬性並組成一個新的型別

interface IPerson {
  name: string
  age: number
  sex: string
}

type IPick = Pick<IPerson, 'name' | 'age'>


let p1: IPick = {
  name: 'lin',
  age: 18
}
  • 實現原理:第一個引數是要抽取的目標物件,第二個引數K:有個約束是K一定要是來自T所有屬性字面量的聯合型別
type Pick<T, K extends keyof T> = {
    [P in K]: T[P]
}

Record
前面三種只作用於obj屬性而不會引入新的屬性,稱為同態
record是會建立新屬性的非同態對映型別

interface IPerson {
  name: string
  age: number
}

type IRecord = Record<string, IPerson>

let personMap: IRecord = {
   person1: {
       name: 'lin',
       age: 18
   },
   person2: {
       name: 'liu',
       age: 25
   } 
}
  • 實現原理:
    • 第一個引數可以傳入繼承於any的任何值
    • 第二個引數,作為新建立物件的值,被傳入
type Record<K extends keyof any, T> = {
    [P in K]: T
}

條件型別

T extends U ? X : Y

Exclude
Exclude 意思是不包含,Exclude<T, U> 會返回 聯合型別 T 中不包含 聯合型別 U 的部分

type Test = Excludes<'a'|'b'|'c','a'>
//返回的Test就是 ‘b’|'c'

-實現原理:

type Exclude<T, U> = T extends U ? never : T
never表示一個不存在的型別
never與其他型別的聯合後,為其他型別
type Test = string | number | never 
就是type Test = string | number

Extract
Extract<T, U>提取聯合型別 T 和聯合型別 U 的所有交集

type Test = Extract<'key1' | 'key2', 'key1'>
Test型別就是key1
  • 實現原理:
type Extract<T,U> = T extends U ? T: never

工具型別

上文的索引型別,對映型別和條件型別都是工具型別

omit

  • Omit<T,U> 從型別T中剔除U中的所有屬性

NonNullable

  • NonNullable用來過濾型別中的null及undefined型別

Parameters

  • 獲取函式的引數型別,將每個引數型別放在一個元組裡

ReturnType

  • 獲取函式的返回值型別