前端進階 -- TS相關

Bill發表於2023-01-19

TS相關

基本概念

型別註解:ts裡的型別註解是一種輕量級的為函式或變數新增約束的方式

基礎型別

布林值、數字、字串、陣列、元組、列舉、any、void、null、undefined、never、object

any、unknown、never、void

定義

  • any:任意型別的變數
  • unknown:表示未知型別
  • never:永不存在的值的型別
  • void:無任何型別,沒有型別

unknown與any類似,但使用前必須進行斷言或守衛,從型別推導來講,unknown是最高階型別,any是unknown的下一級

nerver、void用於函式時,never表示函式用於執行不到返回值那一步(丟擲異常或死迴圈)的返回值型別,即用不存在的值的型別,而void則表示沒有返回值,不返回或返回undefined。從型別推導來講,never是最低層,void與any同級

使用

  • 能不使用any就不用
  • 宣告時如果不確定具體的型別,則可以使用unknown代替,在使用時用型別斷言或型別守衛進行型別收縮
  • never常用於構造條件型別來組合出更靈活的型別定義
  • void常用於表示型別沒有返回值

擴充套件

any與unknown

在原先的typescript中,any屬於top type(最高階型別),在typescript3.0中,unknown才是top type

如果不縮小型別,就無法對unknown型別執行任何操作

function getDog() {
  return '22'
}
cosnt dog: unknown = getDog()
dog.hello() // Object is of type 'unknown'

ts高階用法

  • 介面(interface)可以描述一個物件或者函式
  • 類(class)
  • 函式
  • 泛型
  • 列舉
  • 迭代器和生成器
  • 裝飾器
  • 繼承、多型、過載、重寫
  • 抽象類&抽象方法

具體使用示例可以看官網

TS編譯原理

graph LR
原始碼 --> 掃描器(scanner) --> Token流(中間產物) --> 解析器(parser) --> AST
AST --> 檢查器(checker) --> 型別檢查功能
AST --> 繫結器(binder) --> symbois(符號) -.- 檢查器(checker) -.- 發射器
AST --> 發射器(emitter) --> javascript程式碼

實線為主流程,有三條,虛線為獨立流程,符號單獨指向了檢查器,檢查器單獨指向了發射器

總的來說是

graph LR
sourceCode --> 掃描器 --> token流 --> 解析器 --> ast

token流和ast類似,是掃描之後轉換程式碼的一箇中間產物,也是一個物件,不過key和value不一樣,但是總體構成是類似的

型別推論圖

graph
unknown --> any
any --> null
any --> number -.- never
any --> bigint -.- never
any --> boolean -.- never
any --> string -.- never
any --> object --> array --> tuple -.- never
object --> function -.- never
any --> void --> undefined

面試題

  • 以下程式碼ts推論出來的型別是什麼
let a = 1024 // number
let b = '1024' // string
const c = 'apple' // null,const型別推論出來的都是null
let d = [true, false, true] // array,準確來說是boolean[]
let e = {name: 'apple'} // object
let f = null // null
  • 可賦值性

子集可以賦值給超集,超集不能賦值給子集,除非做出斷言

function a(input: string): string {
  return input
}
function b(iniput: string | number) {
  return input
}
// a可以直接賦值給b
let input = a()
b(input)
// 斷言方法1:as關鍵字
let input = b()
a(input as string)
// 斷言方法2:透過泛型固定引數型別
a(<string>input)

type與interface異同

在官方文件裡,描述type的作用是為型別起別名,interface則是側重描述資料結構的(比如一個物件裡包含了什麼屬性)

用法

  • type
type age = number
type dataType = number | string
type method = 'GET' | 'POST' | 'PUT' | 'DELETE'
type User = {
  name: string
  age: number
}
// 合併type
type name = {
  name: string
}
type User = name & {age: string}
  • interface
interface User {
  name: string
  age: number
}
// 合併interface
interface Admin extends User {
  id: number
}
// interface 也可以合併type
type User = {
  name: string
  age: number
}
interface Admin extends User {
  id: number
}

共同點

  • 都可以描述一個物件或函式
  • interface和type都可以互相擴充,語法上不同,interface使用extends關鍵字,type是用&符號

不同點

  • type可以用於其他型別(聯合型別、元組型別、基本型別(原始值)),interface不支援
type PointX = {x: number}
type PointY = {y: number}
//聯合
type Point = PointX | PointY
// 元組
type Data = [PointX, PointY]
// 原始值
type Name = Number
// typeof的返回值
let div = document.createElement('div')
type B = typeof div
  • interface可以多次定義,並自動合併所有成員變數,type不支援
  • type能使用in關鍵字生成對映型別,interface不支援
type Keys = 'firstname' | 'surname'
type DudeType = {
  [key in Keys]: string
}
// 等同於
type DudeType = {
  firstname: string
  surname: string
}

裝飾器問題

執行順序

  • 有多個引數裝飾器時,從最後一個引數依次向前執行,也就是說裝飾器執行順序是倒序的
  • 方法和方法引數中引數裝飾器先執行
  • 類裝飾器總是最後執行
  • 方法和屬性裝飾器,誰在前面誰先執行,因為引數是屬於方法一部分,所以引數會一直緊緊挨著方法執行

介面型別

  • 屬性類介面
  • 函式類介面
  • 可索引介面
  • 類型別介面
  • 擴充套件介面

相關文章