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

能否实现类型安全函数:从联合类型数组筛选单一类型数组?

实现类型安全的联合类型数组过滤函数

完全可以实现,核心是结合类型守卫函数与泛型,解决你原代码中试图在运行时判断泛型类型的问题(TypeScript类型在运行时会被擦除,无法直接通过T extends Book这类语法判断)。

以下是两种可行的实现方案:


方案一:通用型过滤函数(推荐)

通过传入类型守卫函数,让泛型自动推断目标类型,同时保证运行时过滤逻辑的正确性:

interface Book {
  age: number;
  pages: number;
}

interface Rock {
  age: number;
  shape: string;
}

// 定义互斥的联合类型(可选的never字段让类型约束更严格)
type BookOrRock = (Book & { shape?: never }) | (Rock & { pages?: never });

// 类型守卫:判断是否为Book
const isBook = (x: BookOrRock): x is Book => 'pages' in x;
// 类型守卫:判断是否为Rock
const isRock = (x: BookOrRock): x is Rock => 'shape' in x;

// 通用过滤函数
const filterByType = <T extends BookOrRock>(
  array: BookOrRock[],
  typeGuard: (item: BookOrRock) => item is T
): T[] => {
  const filtered: T[] = [];
  for (const item of array) {
    if (typeGuard(item)) {
      filtered.push(item);
    }
  }
  return filtered;
};

// 测试用例
const booksAndRocks: BookOrRock[] = [
  { age: 1, pages: 100 },
  { age: 1e9, shape: 'round' },
];

// 自动推断为Rock[]类型
const rocks = filterByType(booksAndRocks, isRock);
// 自动推断为Book[]类型
const books = filterByType(booksAndRocks, isBook);

核心逻辑说明:

  • 类型守卫函数isBook/isRock同时承担运行时类型判断和编译时类型推断的作用,告诉TypeScript如何识别目标子类型。
  • 泛型T会根据传入的类型守卫自动推导,返回的数组类型严格对应T[],完全满足类型安全要求。

方案二:重载函数(简化调用)

如果希望通过指定类型标识而非传入守卫函数来调用,可以用函数重载实现:

// 复用之前的接口、联合类型和类型守卫

// 函数重载签名:指定不同调用场景的返回类型
function getOnlyBooksOrOnlyRocks(array: BookOrRock[]): Book[];
function getOnlyBooksOrOnlyRocks(array: BookOrRock[], type: 'book'): Book[];
function getOnlyBooksOrOnlyRocks(array: BookOrRock[], type: 'rock'): Rock[];

// 函数实现
function getOnlyBooksOrOnlyRocks(
  array: BookOrRock[],
  type: 'book' | 'rock' = 'book'
): Book[] | Rock[] {
  const filtered: (Book | Rock)[] = [];
  for (const item of array) {
    if ((type === 'book' && isBook(item)) || (type === 'rock' && isRock(item))) {
      filtered.push(item);
    }
  }
  return filtered as Book[] | Rock[];
}

// 使用示例
const rocks = getOnlyBooksOrOnlyRocks(booksAndRocks, 'rock'); // 类型为Rock[]
const books = getOnlyBooksOrOnlyRocks(booksAndRocks); // 类型为Book[]

这种方式通过重载签名让编译器根据传入的type参数自动推断返回类型,调用更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:01:40