TypeScript全解:聯(lián)合類型

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)合枣申,必須通過收窄后才能使用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市看杭,隨后出現(xiàn)的幾起案子忠藤,更是在濱河造成了極大的恐慌,老刑警劉巖楼雹,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件模孩,死亡現(xiàn)場(chǎng)離奇詭異尖阔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)榨咐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門介却,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人块茁,你說我怎么就攤上這事齿坷。” “怎么了数焊?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵永淌,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我佩耳,道長(zhǎng)遂蛀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任蚕愤,我火速辦了婚禮,結(jié)果婚禮上饺蚊,老公的妹妹穿的比我還像新娘萍诱。我一直安慰自己,他們只是感情好污呼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布裕坊。 她就那樣靜靜地躺著,像睡著了一般燕酷。 火紅的嫁衣襯著肌膚如雪籍凝。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天苗缩,我揣著相機(jī)與錄音饵蒂,去河邊找鬼。 笑死酱讶,一個(gè)胖子當(dāng)著我的面吹牛退盯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泻肯,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼渊迁,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了灶挟?” 一聲冷哼從身側(cè)響起琉朽,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎稚铣,沒想到半個(gè)月后箱叁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墅垮,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年蝌蹂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了噩斟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡孤个,死狀恐怖剃允,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情齐鲤,我是刑警寧澤斥废,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站给郊,受9級(jí)特大地震影響牡肉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淆九,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一统锤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炭庙,春花似錦饲窿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腻脏,卻和暖如春鸦泳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背永品。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工做鹰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鼎姐。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓誊垢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親症见。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喂走,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容