这篇笔记主要记录TypeScript的类型谓词(Type Predicate)和类型断言(Type Assertion).
- 什么是类型谓词
- 什么是类型断言
- 类型谓词和类型断言之间的区别
1. 类型谓词(Type Predicate)
定义: 类型谓词是用于定义一个函数的返回类型的特殊语法,表示该函数会检查一个变量的类型,并返回一个布尔值,告诉TypeScript编译器该变量是否属于某个特定类型。
语法: 看下 TypeScript 文档 parameterName is Type, 其中 parameterName 必须是当前函数签名中的参数名称。 通常在函数的返回类型位置使用。
作用: 类型谓词主要用于类型保护(Type Guards), 帮助TypeScript在特定条件下理解和确定变量的类型。
function isString(value: unknown): value is string {
return typeof value === 'string';
}
const input: unknown = "Hello";
if (isString(input)) {
// 在这个代码块中,TypeScript 知道input 是string类型
console.log(input.toUpperCase()); // 没有类型错误
}
在上面的例子中,isString函数使用类型谓词value is string, 告诉TypeScript, 如果函数返回true,那么value是string类型
在Vue3的源码中,大量用到了类型谓词,
export const isArray = Array.isArray
export const isMap = (val: unknown): val is Map<any, any> =>
toTypeString(val) === '[object Map]'
export const isSet = (val: unknown): val is Set<any> =>
toTypeString(val) === '[object Set]'
export const isDate = (val: unknown): val is Date =>
toTypeString(val) === '[object Date]'
export const isRegExp = (val: unknown): val is RegExp =>
toTypeString(val) === '[object RegExp]'
export const isFunction = (val: unknown): val is Function =>
typeof val === 'function'
export const isString = (val: unknown): val is string => typeof val === 'string'
export const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'
export const isObject = (val: unknown): val is Record<any, any> =>
val !== null && typeof val === 'object'
- 类型断言
有时候你会有一个值的类型信息,而TypeScript不知道。
比如啊,当你使用 document.getElementById 时,TypeScript 只知道这将返回某种类型的 HTMLElement,但你可能知道你的页面中总是会有一个具有特定 ID 的 HTMLCanvasElement。
在这种情况下,你可以使用类型断言来指定一个更具体的类型。
const myCanvas = document.getElementById("main_canvas")
像类型注解一样,类型断言会被编译器移除,并且不会影响代码的运行时行为。
你也可以使用尖括号语法(除了在 .tsx 文件中),它是等效的:
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
提醒:由于类型断言会在编译时被移除,因此与类型断言相关的运行时检查是不存在的。如果类型断言错误,不会生成异常或
null。
定义: 类型断言是一种手动告诉TypeScript编译器将一个值视为某种特定类型的方式,通常用于绕过编译器的类型检查,或在编译器不能自动推断类型时指定类型。
语法: 两种语法形式
- value
- value as Type
作用: 类型断言强制 TypeScript 将某个值视为特定类型,即使编译器可能认为它是另一种类型。它不会进行实际的类型转换,只是在编译时告诉 TypeScript "我知道这个值的类型,请按我说的来处理"。
let someValue: unknown = "Hello, TypeScript";
// 使用类型断言告诉 TypeScript 将 someValue 视为 string 类型
let strLength: number = (someValue as string).length;
// 或者使用另一种语法
let strLengthAlternative: number = (<string>someValue).length;
看下Vue源码 使用类型断言的部分,用到的地方很多,截取了renderer部分
function ensureHydrationRenderer() {
renderer = enabledHydration
? renderer
: createHydrationRenderer(rendererOptions)
enabledHydration = true
return renderer as HydrationRenderer
}
// use explicit type casts here to avoid import() calls in rolled-up d.ts
export const render = ((...args) => {
ensureRenderer().render(...args)
}) as RootRenderFunction<Element | ShadowRoot>
baseHandlers.ts
function hasOwnProperty(this: object, key: unknown) {
// #10455 hasOwnProperty may be called with non-string values
if (!isSymbol(key)) key = String(key)
const obj = toRaw(this)
track(obj, TrackOpTypes.HAS, key)
return obj.hasOwnProperty(key as string)
}
区别总结
-
类型谓词 是一种用于类型保护的工具,帮助 TypeScript 在函数中确定和收窄变量的类型。它是动态检查类型并帮助编译器理解代码。
-
类型断言 是一种静态工具,用于告诉 TypeScript 编译器将一个值视为特定类型,而无需进行任何实际的运行时检查或转换。它通常用于绕过编译器的类型检查,或者当开发者比编译器更清楚某个值的类型时使用。