Last updated on Oct 6, 2022
在 TypeScript 中存在两种功能不同的 typeof 操作符。
typeof,对于基本类型(除了 null)都能返回正确的类型const str = 'Samuel'
const obj = { name: 'Samuel' }
const nullVar = null
const undefinedVar = undefined
const func = (input: string) => {
return input.length > 10
}
type Str = typeof str // 'Samuel'
type Obj = typeof obj // { name: string; }
type Null = typeof nullVar // null
type Undefined = typeof undefinedVar // undefined
type Func = typeof func // (input: string) => boolean
除了可以在类型标注中使用 typeof,还能在工具类型中使用 typeof
const func = (input: string) => {
return input.length > 10
}
type Func = typeof func // (input: string) => boolean
const func2: typeof func = (name: string) => {
return name === 'Samuel'
}
// boolean
type FuncReturnType = ReturnType<typeof func>
大多数情况下,typeof 返回的类型是最窄的推导类型(即到字面量类型的级别)
这两种 typeof 混用了怎么解决?
在逻辑代码中使用的 typeof 一定会是 JavaScript 中的 typeof
而类型代码(如类型标注、类型别名中等)中的一定是 TypeScript 中类型查询的 typeof
为了更好地避免这种情况,最好隔离类型层和逻辑层。另外类型查询操作符后是不允许使用表达式的
const func = (input: string) => {
return input.length > 10
}
// X 不允许表达式
let isValid: typeof func('Samuel')
TypeScript 提供了强大的类型推导能力,会随着代码逻辑不断尝试收窄类型,这就是类型的控制流分析(简单理解为:类型推导)
declare const strOrNumOrBool: string | number
if (typeof strOrNumOrBool === 'string') {
// 一定是字符串
strOrNumOrBool.charAt(1)
} else if (typeof strOrNumOrBool === 'number') {
// 一定是数字
strOrNumOrBool.toFixed()
} else {
// 要是走到这里就说明有问题!
const _exhaustiveCheck: never = strOrNumOrBool
throw new Error(`Unknown input type: ${_exhaustiveCheck}`)
}
通过在 if 条件中的表达式进行了类型保护,从逻辑中进行类型地推导,再反过来让类型为逻辑提供保障。
但类型的控制流分析做不到跨函数上下文来进行类型的信息收集。