Typescript - 共享方法但不派生自共享基类的类



基本上我的设置是 我有一个库,其中包含一堆类 A、B、...、Z 所有这些类都共享一个称为 foo 的通用方法,但它们都不是从基类派生的。

这些方法接受参数,数据,其类型为 AT、BT、...、ZT

例如

class B {
foo(data: BT)
}

class Q {
foo(data: QT);
}

在我的代码中,我必须做一些非常重复的事情,归根结底是创建一个方法,该方法接受一个类(例如 A(和一个数据对象(例如 AT( 类型,然后用数据对象在该类对象上调用 foo。

在打字稿中,有没有一种很好的方法,我可以只有一个辅助函数,而不必编写一堆样板代码

即今天我做

createA(data: AT): A {
let a: A;
a.foo(data);
return a;
}
createB(data: BT): B {
let b: B;
b.foo(data);
return b;
}
...
createZ(data: ZT): Z {
let z: Z;
z.foo(data);
return z;
}

我希望能够做

createObject<ClassType, ArgumentType>(data: ArgumentType): ClassType {
let myObj: ClassType;
myObj.foo(data);
return myObj;
}

谢谢

旁注:像let b: B;这样的代码实际上并没有创建类型B的对象;在运行时,b将被undefined,并且尝试调用其foo()方法时会遇到直接问题。 我假设/希望在您的实际代码中您实际上是在构造B等实例。 但这意味着您应该将类构造函数传递给createObject()函数。 对于其余的答案,我忽略了这一点,并且将或多或少地按原样使用您的签名和实现。 请注意。


你可以像这样编写泛型函数:

function createObject<C extends { foo(a: A): void }, A>(data: A): C {
let myObj: C = null!; // <-- this isn't initialized?
myObj.foo(data);
return myObj;
}

我们使用泛型约束来告诉编译器C将有一个采用A类型参数的foo()方法。 然后,您应该能够调用它:

declare const qt: QT;
const obj = createObject<Q, QT>(qt); // okay, type Q

请注意,如果您希望看到强类型输出,则需要在此处在调用函数时手动指定CA类型参数:

const oops = createObject(qt); //
// const oops: { foo(a: QT): void; }

如果希望编译器从输入类型推断输出类型,则需要createObject()提供一个调用签名,告诉编译器您关心的每个输入-输出映射:

type IOMap = [QT, Q] | [BT, B] // | ... | [ZT, Z];
type ClassType<A extends IOMap[0]> = Extract<IOMap, [A, any]>[1];
function createObject<A extends IOMap[0]>(data: A): ClassType<A>;
function createObject<C extends { foo(a: A): void }, A>(data: A): C {
let myObj: C = null!; // <-- this isn't initialized?
myObj.foo(data);
return myObj;
}

声明起来有点烦人,但更容易使用:

const obj = createObject(qt); // okay
// const obj: Q

好的,希望有帮助;祝你好运!

操场链接到代码

最新更新