You need to enable JavaScript to run this app. TypeScript 类型定义中如何通用校验元组全元素实现属性交集筛选
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 类型定义中如何通用校验元组全元素实现属性交集筛选

需求场景

我们需要基于两个类型提取集合交集:筛选出StyleProperties中「所有元组元素都属于DOMRectReadOnly键集合」的属性键。

  • DOMRectReadOnly的可用键为:width/height/left/top/right/bottom
  • 原始的StyleProperties结构如下,属性值均为不定长度的元组:
interface DOMRectReadOnly {
  readonly width: number;
  readonly height: number;
  readonly left: number;
  readonly top: number;
  readonly right: number;
  readonly bottom: number;
  // 其余属性省略
}

interface StyleProperties {
  size: ["width", "height"];
  start: ["left", "top", "x", "y"],
  end: ["right", "bottom"];
}
原有实现的问题

最初的类型写法只能枚举元组的前两位元素:

type DOMRectStyleProperties = {
  [P in keyof StyleProperties]:
    (StyleProperties[P][0] | StyleProperties[P][1]) extends keyof DOMRectReadOnly
    ? P
    : never
}[keyof StyleProperties];

这种写法无法适配元组长度不固定、元素数量更多的场景,手动枚举所有索引的联合类型完全不可维护。

通用实现方案

通过递归遍历元组的所有元素,实现任意长度元组的全量校验,同时兼容只读元组场景。

基础工具类型

// 获取非空元组的第一个元素,空元组返回never
type First<T extends readonly any[]> = T['length'] extends 0 ? never : T[0];

// 移除元组的第一个元素,返回剩余部分
type Shift<T extends readonly any[]> = T extends readonly [any, ...infer rest] ? rest : never;

// 递归校验元组所有元素是否都符合指定匹配类型,全部匹配则返回原元组,否则返回never
type PickTuple<
  Matcher extends any, 
  Tuple extends readonly any[], 
  Accumulation extends any[] = []
> = Tuple['length'] extends 0
  // 元组遍历完成时,若累积的匹配数组为空则返回never,否则返回累积的匹配结果
  ? Accumulation['length'] extends 0 ? never : Accumulation
  : First<Tuple> extends Matcher
    // 当前元素匹配时,加入累积数组后继续遍历剩余元组
    ? PickTuple<Matcher, Shift<Tuple>, [...Accumulation, First<Tuple>]>
    // 任意一个元素不匹配,直接返回never
    : never;

类型适配调整

由于TS默认会把接口中定义的元组类型放宽为普通数组,且丢失字面量信息,因此需要将StyleProperties调整为常量对象,通过as const修饰保留字面量元组的完整信息:

export const StyleProperties = {
  size: ["width", "height"] as const,
  start: ["left", "top"] as const,
  end: ["right", "bottom"] as const
};

最终类型生成逻辑

type DOMRectStyleProperties = {
  [P in keyof typeof StyleProperties]: 
    // 仅当元组所有元素都属于`keyof DOMRectReadOnly`时保留当前键,否则设为never
    PickTuple<keyof DOMRectReadOnly, typeof StyleProperties[P]> extends never ? never : P
// 索引访问过滤掉所有never项,得到最终的有效键联合类型
}[keyof typeof StyleProperties];
效果说明

上述实现完全不需要关注元组长度:

  • 若元组中存在不属于DOMRectReadOnly的元素(比如示例中start包含的x/y),递归校验会在碰到第一个不匹配元素时直接返回never,对应的start键会被自动过滤
  • 最终输出的DOMRectStyleProperties会自动匹配符合要求的键,示例场景下输出为 "size" | "end"

内容的提问来源于stack exchange,提问作者Changdae Park

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 23:06:07