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

如何让TypeScript类型支持数组?实现AllAttributes与AnyAttribute

解决TypeScript多继承属性聚合问题

原代码结构

原代码中Definition的superDef为单个父类型,通过递归实现了属性的链式聚合:

type Definition<SuperDef extends string, Attributes extends string[]> = {
  superDef: SuperDef;
  attributes: Attributes;
}

interface Definitions {
  'foo': Definition<'', ['a']>;
  'bar': Definition<'foo', ['b']>;
  'baz': Definition<'bar', ['c']>;
}

type SuperDef<Name extends keyof Definitions> = Definitions[Name]['superDef'];
type Attributes<Name extends keyof Definitions> = Definitions[Name]['attributes'];

type AllAttributes<Name extends keyof Definitions> =
    Name extends keyof Definitions
        ? SuperDef<Name> extends keyof Definitions
            ? [...AllAttributes<SuperDef<Name>>, ...Attributes<Name>]
            : Attributes<Name>
        : never;

type AnyAttribute<Name extends keyof Definitions> = AllAttributes<Name>[number];

// AllAttributes<'baz'> = ['a', 'b', 'c']
// AnyAttribute<'baz'> = 'a' | 'b' | 'c'

修改需求

将Definition的superDef改为数组类型SuperDefs,支持多父类型继承,需重新实现AllAttributes(保持属性顺序)和AnyAttribute(基于前者):

type Definition<SuperDefs extends (keyof Definitions)[], Attributes extends string[]> = {
  superDefs: SuperDefs;
  attributes: Attributes;
}

interface Definitions {
  'foo': Definition<[], ['a']>;
  'bar': Definition<['foo'], ['b']>;
  'baz': Definition<['foo'], ['c']>;
  'qux': Definition<['bar', 'baz'], ['d']>;
}

// 期望结果:
// AllAttributes<'baz'> = ['a', 'c']
// AnyAttribute<'baz'> = 'a' | 'c'
// AllAttributes<'qux'> = ['a', 'b', 'c', 'd']
// AnyAttribute<'qux'> = 'a' | 'b' | 'c' | 'd'

解决方案

1. 实现AnyAttribute(核心需求)

直接递归遍历当前类型的所有父类型,合并自身属性与父类型的属性联合:

type Attributes<Name extends keyof Definitions> = Definitions[Name]['attributes'];
type SuperDefs<Name extends keyof Definitions> = Definitions[Name]['superDefs'];

// 提取当前类型及所有父类型的属性联合
type AnyAttribute<Name extends keyof Definitions> = 
  Name extends keyof Definitions 
    ? Attributes<Name>[number] | AnyAttribute<SuperDefs<Name>[number]>
    : never;

2. 实现AllAttributes(保持顺序)

通过递归遍历父类型数组拼接属性,同时可选添加去重逻辑避免重复属性:

// 递归遍历父类型数组,拼接所有父类型的属性
type MergeParentAttributes<Parents extends (keyof Definitions)[]> = 
  Parents extends [infer First extends keyof Definitions, ...infer Rest extends (keyof Definitions)[]]
    ? [...AllAttributes<First>, ...MergeParentAttributes<Rest>]
    : [];

// 可选:数组去重辅助类型
type UniqueArray<T extends any[]> = 
  T extends [infer First, ...infer Rest]
    ? First extends Rest[number]
      ? UniqueArray<Rest>
      : [First, ...UniqueArray<Rest>]
    : [];

// 聚合自身属性与所有父类型属性
type AllAttributes<Name extends keyof Definitions> = 
  Name extends keyof Definitions
    ? UniqueArray<[...MergeParentAttributes<SuperDefs<Name>>, ...Attributes<Name>]>
    : [];

完整验证代码

type Definition<SuperDefs extends (keyof Definitions)[], Attributes extends string[]> = {
  superDefs: SuperDefs;
  attributes: Attributes;
}

interface Definitions {
  'foo': Definition<[], ['a']>;
  'bar': Definition<['foo'], ['b']>;
  'baz': Definition<['foo'], ['c']>;
  'qux': Definition<['bar', 'baz'], ['d']>;
}

type Attributes<Name extends keyof Definitions> = Definitions[Name]['attributes'];
type SuperDefs<Name extends keyof Definitions> = Definitions[Name]['superDefs'];

// AnyAttribute 实现
type AnyAttribute<Name extends keyof Definitions> = 
  Name extends keyof Definitions 
    ? Attributes<Name>[number] | AnyAttribute<SuperDefs<Name>[number]>
    : never;

// AllAttributes 实现(带去重)
type MergeParentAttributes<Parents extends (keyof Definitions)[]> = 
  Parents extends [infer First extends keyof Definitions, ...infer Rest extends (keyof Definitions)[]]
    ? [...AllAttributes<First>, ...MergeParentAttributes<Rest>]
    : [];

type UniqueArray<T extends any[]> = 
  T extends [infer First, ...infer Rest]
    ? First extends Rest[number]
      ? UniqueArray<Rest>
      : [First, ...UniqueArray<Rest>]
    : [];

type AllAttributes<Name extends keyof Definitions> = 
  Name extends keyof Definitions
    ? UniqueArray<[...MergeParentAttributes<SuperDefs<Name>>, ...Attributes<Name>]>
    : [];

// 验证结果
type TestBazAll = AllAttributes<'baz'>; // ['a', 'c']
type TestBazAny = AnyAttribute<'baz'>; // 'a' | 'c'
type TestQuxAll = AllAttributes<'qux'>; // ['a', 'b', 'c', 'd']
type TestQuxAny = AnyAttribute<'qux'>; // 'a' | 'b' | 'c' | 'd'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:08:12