(以下使用TS3.1:)
这个答案充满了警告,以至于我即使发布它也感到很奇怪。另外,我真的不认为我理解你的用例。但是在列表中查找最具体的类型所涉及的类型杂耍激起了我的好奇心。所以我们来了!
以下可以只可能工作如果你传递给的对象x
至少包含一个元素instanceof
传递的每个其他值的构造函数。这意味着类层次结构中没有分叉(或者至少在您传递给的事物列表中没有分叉)x
)并且它是使用原型继承的实际类层次结构。
开始:
type NotExtendsAll<T, U> = U extends any ? [T] extends [U] ? never : unknown : never;
type AbsorbUnion<T> = [T] extends [infer U] ? U extends any ?
NotExtendsAll<U, T> extends never ? U : never : never : never;
type Absorb<T extends any[]> = AbsorbUnion<{ [K in keyof T]: [T[K]] }[number]>[0];
function x<T extends any[]>(...args: T): Absorb<T> extends never ? undefined : Absorb<T>;
function x(...args: any[]): any {
return args.find(a => (args.every(b => a instanceof b.constructor)));
}
解释有点复杂,因为它使用了很多条件类型, 尤其分散式允许您检查工会成员的那些。效果是这样的Absorb<>
接受一个数组(或tuple) 类型并返回所有其他元素的子类型的元素(如果有的话)...否则它将成为底部类型never.
In the x
函数我还使用剩余参数而不是数组,因为它有帮助推断元组类型对于传入的参数。
让我们看看它是否有效:
class A { a: string = "a" }
class B extends A { b: string = "b" }
class C extends B { c: string = "c" }
let a = new A();
let b = new B();
let c = new C();
const aaa = x(a, a, a); // type is A, returns a at runtime
const aba = x(a, b, a); // type is B, returns b at runtime
const abc = x(a, b, c); // type is C, returns c at runtime
我认为看起来不错。
现在,这不起作用:
const none = x(); // type is never, returns undefined at runtime
我知道你想要这样A
,但你没有给它任何参数。它如何返回类型的值A
当它没有的时候?哦,好吧,我们假设有一个名为a
在外部范围中定义。您可以修改上面的内容来制作零参数x()
work:
function otherX<T extends A[]>(...args: T): Absorb<T> extends never ? A : Absorb<T>;
function otherX(...args: A[]): A {
return args.find(z => (args.every(b => z instanceof b.constructor))) || a;
}
const none = otherX(); // type is A, returns a at runtime
const otherAba = otherX(a, b, a); // type is B, returns B at runtime
const otherAbc = otherX(a, b, c); // type is C, returns C at runtime
这里有一些警告......如果您使用带分叉的层次结构:
class D extends A { d: string = "d" }
let d = new D();
const whoops = x(a, b, c, d); // type is undefined, returns undefined at runtime
const alsoWhoops = otherX(b, c, d); // type is A, returns a at runtime
如果您使用非类实例:
const huh = x("a","b","c"); // type is supposedly string, returns undefined at runtime
也许其他疯狂的事情也可能发生。但这是我能得到的最接近的结果。希望对您有帮助。祝你好运!