TypeScript类型谓词和类型断言

554 阅读3分钟

这篇笔记主要记录TypeScript的类型谓词(Type Predicate)和类型断言(Type Assertion).

  1. 什么是类型谓词
  2. 什么是类型断言
  3. 类型谓词和类型断言之间的区别
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,那么valuestring类型

在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'
  
  1. 类型断言

有时候你会有一个值的类型信息,而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 编译器将一个值视为特定类型,而无需进行任何实际的运行时检查或转换。它通常用于绕过编译器的类型检查,或者当开发者比编译器更清楚某个值的类型时使用。