我正在使用自定义库,对于某些类型,我必须编写:
import * as pipeline from 'custom-pipeline';
import {MapTransform} from 'custom-pipeline';
export const createTransform = (appConfig: IAppConfig):
MapTransform<ISomeData, IFoo> |
MapTransform<ISomeData, IBar> => {
switch(appConfig.createType) {
case 'foo':
return new pipeline.MapTransform<ISomeData, IFoo>((data: ISomeData) => {...});
case 'bar':
return new pipeline.MapTransform<ISomeData, IBar>((data: ISomeData) => {...});
}
}
Run Code Online (Sandbox Code Playgroud)
尤其是冗长的构造函数让我很恼火。我可以对类型进行别名:
type FooTransform = MapTransform<ISomeData, IFoo>;
type BarTransform = MapTransform<ISomeData, IBar>;
Run Code Online (Sandbox Code Playgroud)
但我不能这样做:
new FooTransform((data: ISomeData) => {...});
new BarTransform((data: ISomeData) => {...});
Run Code Online (Sandbox Code Playgroud)
抛出一个错误,如:
error TS2304: Cannot find name 'FooTransform'.
Run Code Online (Sandbox Code Playgroud)
我认为这是因为我只有一个类型而不是一个类?然而,我如何才能new FooTransform
以如上所述的方式为构造函数设置别名?
的定义MapTransform
看起来像:
export declare class MapTransform<A, B> extends BaseTransform<A, B> {
constructor(private mapFunc: (val: A) => B);
}
Run Code Online (Sandbox Code Playgroud)
我可以将构造函数简化为:
fooMapFunction = (data: ISomeData): IFoo => {...};
new MapTransform<ISomeData, IFoo>(mapFunction);
Run Code Online (Sandbox Code Playgroud)
尽管它与new FooTransform(fooMapFunction)
.
您的假设是正确的,类型声明是编译时仅,因此您无法对它们执行任何操作(包括使用 实例化new
)。
让我们假设超类看起来像这样:
class MapTransform<T1> {
constructor(public readonly data: T1) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
要创建专门的类型别名,您可以这样做:
type TransformA = MapTransform<number>;
Run Code Online (Sandbox Code Playgroud)
从超类的角度来看,,等等MapTransform
之间没有区别(这是泛型的点),因此我们可以安全地将 class 的构造函数分配给一个常量。调用时,在运行时,相同的调用:MapTransform<A>
MapTransform<B>
MapTransform
TransformA
new TransformA()
new MapTransform<number>()
const TransformA = <{ new (data: number): TransformA; }>MapTransform;
Run Code Online (Sandbox Code Playgroud)
注意到类型断言了吗?这告诉 TypeScript 编译器将分配的值MapTransform
视为一个对象,该对象在TransformA
使用new
. 我们现在可以写:
const a = new TransformA(123);
a.data.toExponential(); // works
Run Code Online (Sandbox Code Playgroud)
顺便说一句,TypeScript 编译器实际看到的是这个......
const TransformA = <{ new (data: number): MapTransform<number>; }>MapTransform;
Run Code Online (Sandbox Code Playgroud)
...因为类型 TransformA ? MapTransform<number>
.
请注意,所有这些都将评估true
:
new TransformA(123) instanceof TransformA
new TransformA(123) instanceof MapTransform
new MapTransform<number>(123) instanceof TransformA
new MapTransform<number>(123) instanceof MapTransform
这是TypeScript Playground 中的示例。
同样,让我们假设超类如下所示:
class MapTransform<T1> {
constructor(public readonly data: T1) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
使用子类化,解决方案很简单:扩展超类并在 extends 子句中传递所需的类型参数。
class TransformA extends MapTransform<number> { }
Run Code Online (Sandbox Code Playgroud)
等等,你现在有一个在运行时工作的构造函数以及一个在编译时工作的类型。
与第一个解决方案不同,以下 2 个表达式将评估true
...
new TransformA(123) instanceof TransformA
new TransformA(123) instanceof MapTransform
...虽然这些将评估false
:
new MapTransform<number>(123) instanceof TransformA
new MapTransform<number>(123) instanceof MapTransform
如果您只需要构造函数别名而不需要类型别名,这可能会派上用场:
const TransformA = class extends MapTransform<number> { };
Run Code Online (Sandbox Code Playgroud)
这称为类表达式,可以像其他所有表达式一样使用,例如:
class App {
private static TransformA = class extends MapTransform<number> { };
public doStuff() {
return new App.TransformA(123);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您有兴趣,这里有更多关于该主题的链接:
您写道,您在将这些解决方案应用于需要函数作为参数的类时遇到了问题,因此这里是 TypeScript playground 中的另一个示例。