typescript - 是否可以声明一个接受超类实例数组并返回最具体的子类类型的函数
问题描述
我正在为我的 Javascript 包编写一个 Typescript 声明文件。
我的库有一个函数,它接受一组超类元素并返回超类。
function x(args: SuperClass[]): SuperClass
我想修改方法的返回类型,使其返回最具体的子类元素的类型。
function x(args: SuperClass[]): TypeOfMostSpecificArg(args)
例如
interface A {}
interface B extends A {}
interface C extends B {}
let a: A, b: B, c: C
x([]) // should have return type A
x([a, b, a]) // should have return type B
x([a, b, c]) // should have return type C
这可能吗?
解决方案
(以下使用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<>
接受一个数组(或元组)类型并返回作为所有其他元素的子类型的元素,如果有的话......否则它成为底部类型never
。
在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()
工作:
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
并且可能还会发生其他疯狂事件。但这是我能得到的最接近的。希望对您有所帮助。祝你好运!
推荐阅读
- python - 修改 DataFrames 的切片:在 pandas 中使用什么来代替 .ix
- javascript - Find key and then replace value
- php - Laravel 5.5 + 图像不可读错误(使用干预\图像)
- c++ - valgrind 在单链接列表示例中显示内存泄漏
- spring - 如何在 Spring Cloud Data Flow 中创建简单的登录?
- c# - JSON 序列化的 ModelState 错误在 ASP.NET Core 2.2 WebApi 中的行为不同
- php - 我如何将 PHP 字符串转换为下面的数组结构
- python - 老化桶分析
- java - Javacv下使用FFmpegFrameGrabber启用ZVBI时如何配置ffmpeg
- python - 从大的时间间隔范围中减去较小的时间间隔