我使用带有依赖注入库的 TypeScript,它的工作方式与 Angular 1 非常相似 - 基本上:使用依赖项作为参数注册一个工厂。
这就是我在 ES6 中注册课程的方式
export let factory = () => {
return class Foo {}
};
如果我在 TypeScript 中写同样的内容:
export let factory = () => {
return class Foo {}
};
编译失败并出现错误
错误 TS4025:导出的变量“factory”具有或正在使用私有名称“Foo”。
有什么方法可以让 TypeScript 从工厂函数返回一个类吗?
更改此:
export let factory = () => {
return class Foo {}
};
对此:
export let factory = () : any => {
return class Foo {}
};
此错误可能由 tsconfig.json 设置触发/强制:
{
"compilerOptions": {
...
"declaration": true // this should be false or omitted
但这不是原因,这只是一个触发因素。真正的原因(如此处讨论的导出返回类的函数时出现错误:导出的变量具有或正在使用私有名称)来自 Typescript 编译器
当 TS 编译器发现这样的语句时
let factory = () => { ...
它必须开始猜测返回类型是什么,因为缺少该信息(检查
: <returnType>
占位符):
let factory = () : <returnType> => { ...
在我们的例子中,TS很快就会发现,返回的
type
很容易猜到:
return class Foo {} // this is returned value,
// that could be treated as a return type of the factory method
所以,如果我们有类似的语句(这与原始语句完全不一样,但让我们尝试用它作为示例来阐明发生的情况)我们可以正确声明返回类型:
export class Foo {} // Foo is exported
export let factory = () : Foo => { // it could be return type of export function
return Foo
};
这种方法会起作用,因为
Foo
我们想要返回类型,即未导出。然后,我们必须帮助 TS 编译器决定返回类型是什么。
可以是任何明确的:
export let factory = () : any => {
return class Foo {}
};
但更好的是有一些公共接口
export interface IFoo {}
然后使用
返回类型这样的接口:
export let factory = () : IFoo => {
return class Foo implements IFoo {}
};
您需要在工厂方法外部定义类并使用“typeof”定义返回值。
class Foo {}
export const factory = (): typeof Foo => {
return Foo;
};
通常工厂会返回一个实例而不是类或构造函数。
更新示例
export class Foo {};
export let factory = () => {
return Foo;
};
使用 ES6,你不需要导出类类型,但使用 TypeScript,你绝对应该导出类型签名。
单独提供的解决方案令人满意:
export class MyClass {
...
}
export type MyClassRef = new (...args: any) => MyClass;
鉴于该签名,我可以使用 MyClassRef
作为返回值类型:
exposeMyClass(): MyClassRef {
return MyClass;
}
"declaration": true
从
tsconfig.json
或将其设置为
false
。
包括静态函数!!!
我使用泛型来确保工厂的每个实现都有不同的结果,但没有什么可以阻止你在工厂函数中使用 if/else 语句
type Animal = {
kind: string,
age: number,
}
type AnimalFactory<T extends Animal> = {
new(): {
sayAge: () => number;
},
validate: (obj: Record<string, unknown>) => obj is T;
}
function AnimalFactory<T extends Animal>(Base: T): AnimalFactory<T> {
return class Animal {
sayAge(): number {
return Base.age;
}
static validate(obj: Record<string, unknown>): obj is T {
return 'kind' in obj
}
}
}
const Dog = AnimalFactory({ kind: 'dog', age: 20 })
const dog = new Dog();
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
class Factory{
getObject(msg:string): Greeter {
return new Greeter(msg);
}
}
var greeter = new Factory().getObject("Hi");
console.log(greeter.greet());