如何让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
相关产品推荐
相关产品推荐

