如何编写TypeScript函数接收子类型继承父类型的元组数组?
如何编写约束元组数组元素子类型关系的TypeScript函数
要实现接收元组数组且每个元组第二个元素是第一个元素子类型(类构造函数而非实例)的函数,有两种简洁的实现方式:
方案一:精准约束类构造函数类型
如果你的场景只针对类(包括抽象类),可以直接定义符合要求的元组类型,再约束参数为该类型的数组:
// 定义合法元组:第一个是抽象/普通类构造函数,第二个是其子类构造函数 type ValidClassTuple = [ Base: abstract new (...args: any[]) => any, Sub: new (...args: any[]) => InstanceType<typeof Base> ]; function foo(x: ValidClassTuple[]): void {} // 测试示例 abstract class A { abstract foo(): any } class B extends A { foo() { throw new Error("Method not implemented.") } } abstract class C { abstract baz(): any } class D extends C { baz() { throw new Error("Method not implemented.") } } // 合法调用:通过类型校验 foo([ [A, B], [C, D] ]) // 非法调用:报错,C不是A的子类 // foo([[A, C]])
这个方案直接针对类构造函数做约束,类型检查更精准,能避免传入非类类型的错误。
方案二:通用子类型约束(支持任意类型)
如果需要支持更通用的子类型关系(不局限于类),可以利用你之前定义的ValidateTuples类型,将其作为函数参数的约束:
type ValidateTuples<T> = T extends Array<[any, any]> ? { [K in keyof T]: T[K] extends [infer A, infer B] ? B extends A ? T[K] : never : never } : never; // 泛型T捕获传入的数组类型,再用ValidateTuples约束其合法性 function foo<T extends Array<[any, any]>>(x: ValidateTuples<T>): void {} // 同样支持合法调用,非法调用会触发类型错误 foo([[A, B], [C, D]]) // foo([[A, C]]) // 报错
分析你之前的尝试问题
- 单泛型约束失效:
function foo<A, B extends A>(x: Array<[A, B]>) {}的问题在于,泛型A和B是全局的,要求数组中所有元组都必须使用同一组A和B。当你传入不同Base的元组(比如[A,B]和[C,D]),TypeScript无法找到一个统一的A满足所有元组,因此报错。 - ValidateTuples的正确用法:你定义的
ValidateTuples类型本身是有效的,只需将它和泛型T结合,让函数参数的类型为ValidateTuples<T>,同时用T捕获传入的原始数组类型,就能实现动态校验每个元组的子类型关系。
内容的提问来源于stack exchange,提问作者shotex
相关产品推荐
相关产品推荐

