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

如何实现满足特定约束的TypeScript泛型NewType工具类型?

泛型类型NewType的实现问题

需求说明

需要实现一个泛型类型NewType,接收字段名Field和可选值集合Params作为参数,需满足以下规则:

  • 合法情况一:设置Field字段为Params中的某一个值,此时所有Params对应的属性必须为never或undefined;
  • 合法情况二:设置Params中的某一个属性为true,此时Field字段必须为never或undefined,且其余Params属性也必须为never或undefined;
  • 排除非法情况:同时设置Field字段和某个Params属性为true,或设置多个Params属性为true。

预期用法示例

type AnimalExample = NewType<"animal","mammal"|"reptile"|"bird">

const example1:AnimalExample = {animal: "bird"} // 合法

const example2:AnimalExample = {animal: "bird", bird: true} // 非法

const example3:AnimalExample = {bird: true} // 合法

const example4:AnimalExample = {bird: true, reptile: true} // 非法

当前实现卡点

现有代码中,第二种合法情况的Partial<Record<Params, boolean>>无法实现分布式逻辑,无法限制只能选一个Params属性设为true:

type NewType<Field extends string, Params extends string> =
  | (Record<Field, Params> & Partial<Record<Params, never>>)
  | (Partial<Record<Field, undefined>> & Partial<Record<Params, boolean>>); // 此处需要实现分布式逻辑

已写出能生成单Params属性为true的联合类型的Test类型,但不知道如何整合进NewType:

type AnimalTypes = "mammal"|"reptile"|"bird"
type Test<T> = T extends AnimalTypes
  ? { [Self in T]: true } & Partial<
      Record<Exclude<AnimalTypes, T>, never>
    >
  : never;

该Test类型生成的结果:

(
  | { mammal: true; reptile?: never; bird?: never }
  | { mammal?: never; reptile: true; bird?: never }
  | { mammal?: never; reptile?: never; bird: true }
)

期望最终结果:

(
  | { animal: "mammal"|"reptile"|"bird"; mammal?: never; reptile?: never; bird?: never }
  | { mammal: true; reptile?: never; bird?: never; animal?: never }
  | { mammal?: never; reptile: true; bird?: never; animal?: never }
  | { mammal?: never; reptile?: never; bird: true; animal?: never }
)

解决方案

把你写的Test类型的分布式逻辑泛化,整合进NewType的第二种情况即可:

type NewType<Field extends string, Params extends string> =
  // 合法情况一:设置Field字段,所有Params属性为never/undefined
  (Record<Field, Params> & Partial<Record<Params, never>>)
  // 合法情况二:设置单个Params属性为true,Field为never/undefined,其余Params属性为never/undefined
  | (Partial<Record<Field, undefined>> & {
      [P in Params]: { [Self in P]: true } & Partial<Record<Exclude<Params, P>, never>>
    }[Params]);

代码解释

  1. 合法情况一:保持原有逻辑,Record<Field, Params>确保Field字段是Params中的值,Partial<Record<Params, never>>限制所有Params属性只能是never或undefined。
  2. 合法情况二:
    • Partial<Record<Field, undefined>>限制Field字段只能是undefined或不存在;
    • 通过{ [P in Params]: ... }[Params]实现分布式联合:遍历Params中的每个类型P,生成一个仅P为true、其余Params属性为never/undefined的对象类型,最终这些类型组成联合类型,自然限制了只能选一个Params属性设为true。

测试该实现,完全符合预期用法的合法/非法判断,也能生成你期望的最终类型结构。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:27:38