You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现TypeScript通用类型守卫函数,合并多守卫推断类型

实现TypeScript通用类型守卫函数:多守卫联合推断交叉类型

需求背景

需要实现一个通用类型守卫函数,接收一个对象和一组类型守卫函数(这些守卫入参类型一致,但断言的目标类型不同),当所有守卫校验通过时,TypeScript能自动推断该对象为所有守卫断言类型的交叉类型。

现有代码中,单个类型守卫能正常推断类型,但使用Array.every批量校验时无法自动推断交叉类型:

type HasFirstName = { firstName: string; };
type HasLastName = { lastName: string; };

const validateHasFirstName = (object: object): object is HasFirstName => 'firstName' in object;
const validateHasLastName = (object: object): object is HasLastName => 'lastName' in object;

const test = {};

// 单个守卫:类型推断正常
if (validateHasFirstName(test)) {
  test.firstName; // ✅ 可访问
}

// 批量校验:无法推断交叉类型
const validators = [validateHasFirstName, validateHasLastName];
if (validators.every(v => v(test))) {
  test.firstName; // ❌ 无法访问,类型未推断
}

// 期望实现的函数形态
function universalValidator(object: object, ...validators) {
  return validators.every(v => v(object));
}

if (universalValidator(test, validateHasFirstName, validateHasLastName)) {
  test.firstName; // 期望此处可正常访问
  test.lastName;
}

解决方案

核心思路是提取每个类型守卫的断言类型,再将这些类型合并为交叉类型,而非直接交叉守卫函数本身。

1. 定义工具类型

// 定义类型守卫函数的通用结构:入参为T,断言为T的子类型U
type TypeGuard<T, U extends T> = (obj: T) => obj is U;

// 从类型守卫函数中提取出它断言的目标类型U
type ExtractGuardType<G> = G extends TypeGuard<any, infer U> ? U : never;

// 将联合类型转换为交叉类型(复用经典实现)
type UnionToIntersection<U> = 
  (U extends any ? (k: U) => void : never) extends (k: infer I) => void 
    ? I 
    : never;

2. 实现通用类型守卫函数

function universalValidator<T, G extends TypeGuard<T, any>>(
  obj: T,
  ...validators: G[]
): obj is T & UnionToIntersection<ExtractGuardType<G>> {
  // 执行所有守卫校验
  return validators.every(validator => validator(obj));
}

3. 测试验证

const test = {};

if (universalValidator(test, validateHasFirstName, validateHasLastName)) {
  test.firstName; // ✅ 类型推断为string,可正常访问
  test.lastName;  // ✅ 类型推断为string,可正常访问
}

关键说明

  • 之前尝试交叉守卫函数本身的方案错误,因为我们需要的是合并断言的类型,而非合并函数类型
  • ExtractGuardType通过条件类型的infer关键字,从守卫函数中提取出它断言的目标类型
  • UnionToIntersection将多个守卫的断言类型(联合类型)转换为交叉类型,确保对象同时满足所有守卫的类型约束
  • 函数泛型T绑定输入对象的原始类型,最终返回的类型断言是T与所有守卫断言类型的交叉,保证类型推断的准确性

内容的提问来源于stack exchange,提问作者Tomáš Hübelbauer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 10:26:04