JS 可以對(duì)值進(jìn)行加減運(yùn)算
如果把 TS 的類型系統(tǒng)的當(dāng)作一門語言筑辨,
TS 可以對(duì)類型進(jìn)行各種運(yùn)算嗎?
如果有,那么 TS 類型系統(tǒng)有那些運(yùn)算呢节猿?
聯(lián)合類型(union type)(也叫做并集)
栗子??
type A1 = number;
type B1 = string;
type C1 = A1 | B1;
const c1: C1 = 42;
上述代碼用圖表示即為:
type A2 = { name: string };
type B2 = { age: number };
type C2 = A2 | B2;
const c2: C2 = {
name: 'John',
age: 18,
}
如何使用?
const f1 = (a: number | string) => {
a.xxx?
// 這里能使用出 a 的那些方法漫雕?
// 即不能把 a 當(dāng)作 number
// 也不能把 a 當(dāng)作 string
// 那么滨嘱,怎么使用 a 變量呢?
}
想辦法把類型取分開來即可:
const f1 = (a: number | string) => {
if (typeof a === 'number') {
a.toFixed(2) // 這里可以調(diào)用 Number 的方法
} else {
a.split('') // 這里可以調(diào)用 String 的方法
}
}
這樣一來浸间,即可保證使用的安全九孩,這種行為也叫類型收窄。
用JS做類型收窄
typeof
js 的 typeof 有以下幾種返回值:
- string
- number
- bigint
- boolean
- symbol
- undefined
- object
- function
我們發(fā)現(xiàn) tpyeof 的有以下的局限性:數(shù)組對(duì)象发框、普通對(duì)象躺彬、日期對(duì)象煤墙、null 都無法區(qū)分
const a = (params: Date | Date[]) => {
if (typeof params === 'object') {
params // 此時(shí)類型仍然為 Date | Date[]
}
}
但是我們還能使用 instanceof
instanceof
這個(gè)方法主要返回對(duì)象的類
const a = (params: Date | Date[]) => {
if (params instanceof Date) {
params // 此時(shí)類型收窄為 Date
} else if (params instanceof Array) {
params // 此時(shí)類型收窄為 Array
}
}
instanceof 的局限性:不支持 TS 獨(dú)有的類型
type Person = {
age: number;
}
type Animal = {
name: string;
}
const a = (params: Person | Animal) => {
if (params instanceof Person) { // TODO: 報(bào)錯(cuò),Person 是一個(gè)類型宪拥,而不是類
// ...
}
}
那么如何解決呢仿野?
in
type Person = {
age: number;
}
type Animal = {
name: string;
}
const a = (params: Person | Animal) => {
if ('name' in params) {
params // 這里的類型為 Animal
} else if ('age' in params) {
params // 這里的類型為 Person
}
}
in 的局限性:只能區(qū)分部分對(duì)象,比如沒有相同屬性的對(duì)象她君、日期對(duì)象脚作、函數(shù)
思考,怎么有這么多的局限性
因?yàn)槲覀円恢痹谟?js 的邏輯來判斷 ts 里面的邏輯缔刹,這是兩門語言球涛,根本無法做到一一對(duì)應(yīng)
更多收窄,見這份文檔
眾所周知:js 的類型系統(tǒng)就是辣雞校镐,那么有沒有取分類型的萬全之法
類型謂詞/類型判斷
is
type Person = {
age: number;
sex: number;
}
type Animal = {
name: string;
legs: string[];
}
const a = (params: Perosn | Animal) => {
if (isPerson(a)) {
params // 這里的類型一定為 Person
}
}
function isPerson(x: Person | Animal /* 這里可以寫 any */): x is Person {
// 這里可以使用上面所有的類型判斷技巧
return 'age' in x && 'sex' in x // 必須返回 boolean
}
const isAnimal = (x: any): x is Animal => 'name' in x && 'legs' in x && a instanceof Array
有點(diǎn)是支持所有 TS 類型亿扁,但是隨之而來的缺點(diǎn)就是 麻煩!那么有沒有更簡(jiǎn)單的方法呢鸟廓?
可辨別聯(lián)合
直接上代碼
type Person = { kind: 'person'; name: string; age: number; }
type Animal = { kind: 'animal'; name: string; }
const a = (params: Person | Animal) => {
if (params.kind === 'person') {
params // 這里的類型為 Person
} elseif (params.kind === 'animal') {
params // 這里的類型為 Animal
}
}
- 優(yōu)點(diǎn):把復(fù)雜類型的收窄變成簡(jiǎn)單類型的對(duì)比
- 局限性:1. 必須加上相同屬性 kind从祝; 2. kind 的類型必須是簡(jiǎn)單類型; 3. 各類型中的 kind 無交集
則稱為可辨別聯(lián)合
斷言
type Person = {
age: number;
}
type Animal = {
name: string;
}
const a = (params: Person | Animal) => {
(params as Person).age // 強(qiáng)制告訴 ts 此時(shí)類型為 Person
}
思考:any 是否等于所有類型(除 never/unknown/any/void)的聯(lián)合?為什么引谜?
答案是不是
之前在基礎(chǔ)類型中介紹過牍陌,并畫過圖,any 包含了所有的類型员咽,但是僅僅限于那個(gè)時(shí)候毒涧,在了解過類型收窄以后,就不能這么理解了贝室。
怎么證明链嘀?用反證法:
正常來說一旦出現(xiàn)聯(lián)合類型,那么這個(gè)時(shí)候你的類型就不能再使用了
const a = (params: number | string) => {
a // 此時(shí)這里只能調(diào)用 number 和 string 的共用方法档玻,無法調(diào)用比如 split 這種字符串特有方法
}
但是如果是 any怀泊,則可以繼續(xù)使用
const a = (params: any) => {
a.split() // 不會(huì)報(bào)錯(cuò)
a.toFixed() // 不會(huì)報(bào)錯(cuò)
}
這個(gè)時(shí)候我們?cè)賮砜纯?a target="_blank">官方文檔
解釋為這是一個(gè)特殊的類型,如果你不想讓你的類型報(bào)錯(cuò)你可以使用這個(gè)類型
其實(shí)文檔也沒有說的很清楚误趴,目前來看 TS 絕大部分規(guī)則對(duì) any 不生效
const a = (params: any) => {
const newParams: never = params // TODO: 報(bào)錯(cuò)
}
那么什么類型等于所有類型(除 never/unknown/any/void)的聯(lián)合呢霹琼?為什么?
答案就是 unknown
const a = (params: unknown) => {
if (typeof === 'number') {
params.toFixed() // 這里的類型是 number
} elseif (params instanceof Data) {
params // 這里的類型是 Date
}
}
也就是說 unknown 可以收窄為任意類型凉当,那么反過來說就是 unknown 就是所有類型的聯(lián)合枣申,必須通過收窄后才能使用