Skip to content

类型缩小

类型缩小:一个较为宽泛的集合缩小到相对较小、较明确的集合

类型守卫

通过类型守卫缩小子类型

js
{
  let func = (anything: any) => {
    if (typeof anything === 'string') {
      return anything // 类型是 string
    } else if (typeof anything === 'number') {
      return anything // 类型是 number
    }
    return null
  }
}

等值判断或流程控制语句

通过字面量类型等值判断(===)或其他控制流语句(包括但不限于 if、三目运算符、switch 分支)将联合类型收敛为更具体的类型

tsx
{
  type Goods = 'pen' | 'pencil' | 'ruler'
  const getPenCost = (item: 'pen') => 2
  const getPencilCost = (item: 'pencil') => 4
  const getRulerCost = (item: 'ruler') => 6
  const getCost = (item: Goods) => {
    if (item === 'pen') {
      return getPenCost(item) // item => 'pen'
    } else if (item === 'pencil') {
      return getPencilCost(item) // item => 'pencil'
    } else {
      return getRulerCost(item) // item => 'ruler'
    }
  }
}

特殊值问题:通过 object 无法排除 null

tsx
const el = document.getElementById('foo') // Type is HTMLElement | null
if (typeof el === 'object') {
  el // Type is HTMLElement | null
}

空字符串和 0:无法通过 !x 排除 number,string,因为 0,'' 都是 falsy 值。

tsx
function foo(x?: number | string | null) {
  if (!x) {
    x // Type is string | number | null | undefined
  }
}

标签联合

放置一个明确标签,帮助 ts 确认类型

tsx
interface UploadEvent {
  type: 'upload'
  filename: string
  contents: string
}

interface DownloadEvent {
  type: 'download'
  filename: string
}

type AppEvent = UploadEvent | DownloadEvent

function handleEvent(e: AppEvent) {
  switch (e.type) {
    case 'download':
      e // Type is DownloadEvent
      break
    case 'upload':
      e // Type is UploadEvent
      break
  }
}