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

如何基于对象属性类型缩小泛型类型?TypeScript工具类型实现

实现TypeScript工具类型ExtractOnProp:从联合类型中提取指定属性匹配目标类型的对象

我需要创建一个TypeScript工具类型ExtractOnProp,作用是从联合类型T中,提取出**指定属性Prop的类型属于目标类型ValueType**的对象。

示例如下:

type ExtractOnProp<T, Prop extends keyof T, ValueType> = /* 待实现 */;

type Test1 = ExtractOnProp<
  | { value: "test1" | "test2", prop1: any }
  | { value: "test1", prop2: any }
  | { value: "test3", prop3: any },
  "value",
  "test1">;
// 期望Test1的结果:{ value: "test1", prop1: any } | { value: "test1", prop2: any };

实际应用场景示例(从数组中筛选匹配元素):

function narrow<
  T extends { value: string },
  Value extends readonly T['value'][],
>(
  elements: readonly T[],
  filter: Value,
): ExtractOnProp<T, 'value', Value[number]> {
  const result = elements.find((el) => filter.includes(el.value as any));
  if (!result) {
    throw new Error('not found');
  }
  return result as any;
}
narrow(
  [
    { value: 'test1', prop1: 1 },
    { value: 'test2', prop1: 2 },
    { value: 'test3', prop3: 3 },
  ] as const,
  ['test1', 'test3'] as const,
);
// 期望返回类型:{ value: 'test1', prop1: 1 } | { value: 'test3', prop3: 3 }

尝试过的实现及问题

最初的错误实现

type ExtractOnProp<T, Prop extends keyof T, ValueType> = T[Prop] extends ValueType ? T : never;
// 问题:始终返回never

属性类型交集实现(仅能提取属性类型)

type IntersectPropType<T, Prop extends keyof T, ValueType> = T[Prop] extends infer S
  ? S extends ValueType
    ? S
    : never
  : never;
type Test1 = IntersectPropType<{ value: 'test1' | 'test2' } | { value: "test3"; prop: any }, 'value', 'test2' | 'omitted'>;
// Test1 = 'test2';
// 问题:只能提取匹配的属性类型,无法返回完整的对象类型

编辑补充后的实现(接近但仍有问题)

type ExtractOnProp<T, Prop extends keyof T, ValueType> = T extends {
  [_ in Prop]: infer S;
}
  ? ValueType extends S
    ? T
    : never
  : never;

type Test = ExtractOnProp<
  { value: 'a' | 'c'; prop1: any } | { value: 'b'; prop2: any },
  'value',
  'a'
>;
// 实际Test结果:{ value: 'a' | 'c', prop1: any }
// 问题:能筛选出符合条件的联合成员,但无法将成员的`value`属性类型缩小为`'a'`

正确的实现方案

要解决这个问题,需要同时完成两个操作:

  1. 从联合类型中筛选出属性Prop与ValueType有交集的成员
  2. 将筛选出的成员的Prop属性类型缩小为ValueType与原属性类型的交集

实现代码如下:

type ExtractOnProp<T, Prop extends keyof T, ValueType> = 
  T extends infer U 
    ? U extends Record<Prop, infer S>
      ? (ValueType & S) extends never
        ? never
        : Omit<U, Prop> & { [P in Prop]: ValueType & S }
      : never
    : never;

验证结果

验证Test1

type Test1 = ExtractOnProp<
  | { value: "test1" | "test2", prop1: any }
  | { value: "test1", prop2: any }
  | { value: "test3", prop3: any },
  "value",
  "test1">;
// Test1结果:{ value: "test1", prop1: any } | { value: "test1", prop2: any }
// 符合预期

验证Test

type Test = ExtractOnProp<
  { value: 'a' | 'c'; prop1: any } | { value: 'b'; prop2: any },
  'value',
  'a'
>;
// Test结果:{ value: 'a', prop1: any }
// 符合预期

验证实际应用场景

function narrow<
  T extends { value: string },
  Value extends readonly T['value'][],
>(
  elements: readonly T[],
  filter: Value,
): ExtractOnProp<T, 'value', Value[number]> {
  const result = elements.find((el) => filter.includes(el.value as any));
  if (!result) {
    throw new Error('not found');
  }
  return result as any;
}
const res = narrow(
  [
    { value: 'test1', prop1: 1 },
    { value: 'test2', prop1: 2 },
    { value: 'test3', prop3: 3 },
  ] as const,
  ['test1', 'test3'] as const,
);
// res的类型:{ value: 'test1', prop1: 1 } | { value: 'test3', prop3: 3 }
// 符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:36:07