在 TypeScript 中使用子类工厂模式时,超类应该是什么类型?
Of what type should a superclass be when using a subclass factory pattern in TypeScript?
我正在尝试在 TypeScript 中实现子类工厂模式 3.x。
考虑这个测试:
import { expect } from 'chai'
describe('subclass factory', () => {
it('should work', () => {
interface INameable {
name?: string
}
const name = 'I am a Nameable!'
function nameableSubclassOf<T> (superclass) {
return class extends superclass implements INameable {
name?: string = name
}
}
class Foo {}
const NameableFoo = nameableSubclassOf(Foo)
const nameableFoo = new NameableFoo()
expect(nameableFoo).to.be.instanceOf(Foo)
expect(nameableFoo.name).to.be.ok
expect(nameableFoo.name).to.equal(name)
})
})
编译失败并显示以下消息:
TSError: ⨯ Unable to compile TypeScript:
src/test/subclass-factory.ts(11,37): error TS7006: Parameter 'superclass' implicitly has an 'any' type.
如何更改以上代码以成功编译和 return 一个 class
是 T
的子类,它还声明它实现了 INameable
?
这边?
function nameableSubclassOf(superclass: {new(): any}) {
我认为您的选择要么是告诉 Typescript superclass
是 new
able,其语法是 briefly alluded to in the TypeScript handbook:
// "new (...args: any[]) => any" means the constructor takes any number of arguments
// and returns anything
function nameableSubclassOf<C extends new (...args: any[]) => any>(superclass: C) {
return class extends superclass implements INameable {
name?: string = name
}
}
这应该允许编译器为 nameableSubclassOf
的 return 值推断出可用但相当不透明的类型:
const NameableFoo = nameableSubclassOf(Foo)
// const NameableFoo: {
// new (...args: any[]): nameableSubclassOf<typeof Foo>.(Anonymous class);
// prototype: nameableSubclassOf<any>.(Anonymous class);
// } & typeof Foo
const nameableFoo = new NameableFoo();
// const nameableFoo: nameableSubclassOf2<typeof Foo>.(Anonymous class) & Foo;
const fooName = nameableFoo.name;
// const fooName: string | undefined;
... 或者,如果你想要一个不依赖于匿名 类 的更明确的类型,你可以使用泛型来指定超类和 conditional types 来提取构造函数参数和return 从中输入:
function nameableSubclassOf<C extends new (...args: any[]) => any>(
superclass: C
): C extends new (...args: infer A) => infer T ? new (...args: A) => T & INameable : never;
function nameableSubclassOf(
superclass: new (...args: any[]) => any
): new (...args: any[]) => INameable {
return class extends superclass implements INameable {
name?: string = name
}
}
请注意,我在实现中使用了单个 overload for the function call signature, which is what the caller sees. The implementation signature is looser because it's hard for the compiler to verify that a value is assignable to a conditional type... so the one-signature-overload is a way to get more type safety for the caller of a function without having to use loads of type assertions。
这更冗长,但是当你使用它时你会得到更好的类型:
const NameableFoo = nameableSubclassOf(Foo)
// const NameableFoo: new () => Foo & INameable
const nameableFoo = new NameableFoo()
// const nameableFoo: Foo & INameable
const fooName = nameableFoo.name
// const fooName: string | undefined
希望其中之一能有所帮助。祝你好运!
我正在尝试在 TypeScript 中实现子类工厂模式 3.x。 考虑这个测试:
import { expect } from 'chai'
describe('subclass factory', () => {
it('should work', () => {
interface INameable {
name?: string
}
const name = 'I am a Nameable!'
function nameableSubclassOf<T> (superclass) {
return class extends superclass implements INameable {
name?: string = name
}
}
class Foo {}
const NameableFoo = nameableSubclassOf(Foo)
const nameableFoo = new NameableFoo()
expect(nameableFoo).to.be.instanceOf(Foo)
expect(nameableFoo.name).to.be.ok
expect(nameableFoo.name).to.equal(name)
})
})
编译失败并显示以下消息:
TSError: ⨯ Unable to compile TypeScript:
src/test/subclass-factory.ts(11,37): error TS7006: Parameter 'superclass' implicitly has an 'any' type.
如何更改以上代码以成功编译和 return 一个 class
是 T
的子类,它还声明它实现了 INameable
?
这边?
function nameableSubclassOf(superclass: {new(): any}) {
我认为您的选择要么是告诉 Typescript superclass
是 new
able,其语法是 briefly alluded to in the TypeScript handbook:
// "new (...args: any[]) => any" means the constructor takes any number of arguments
// and returns anything
function nameableSubclassOf<C extends new (...args: any[]) => any>(superclass: C) {
return class extends superclass implements INameable {
name?: string = name
}
}
这应该允许编译器为 nameableSubclassOf
的 return 值推断出可用但相当不透明的类型:
const NameableFoo = nameableSubclassOf(Foo)
// const NameableFoo: {
// new (...args: any[]): nameableSubclassOf<typeof Foo>.(Anonymous class);
// prototype: nameableSubclassOf<any>.(Anonymous class);
// } & typeof Foo
const nameableFoo = new NameableFoo();
// const nameableFoo: nameableSubclassOf2<typeof Foo>.(Anonymous class) & Foo;
const fooName = nameableFoo.name;
// const fooName: string | undefined;
... 或者,如果你想要一个不依赖于匿名 类 的更明确的类型,你可以使用泛型来指定超类和 conditional types 来提取构造函数参数和return 从中输入:
function nameableSubclassOf<C extends new (...args: any[]) => any>(
superclass: C
): C extends new (...args: infer A) => infer T ? new (...args: A) => T & INameable : never;
function nameableSubclassOf(
superclass: new (...args: any[]) => any
): new (...args: any[]) => INameable {
return class extends superclass implements INameable {
name?: string = name
}
}
请注意,我在实现中使用了单个 overload for the function call signature, which is what the caller sees. The implementation signature is looser because it's hard for the compiler to verify that a value is assignable to a conditional type... so the one-signature-overload is a way to get more type safety for the caller of a function without having to use loads of type assertions。
这更冗长,但是当你使用它时你会得到更好的类型:
const NameableFoo = nameableSubclassOf(Foo)
// const NameableFoo: new () => Foo & INameable
const nameableFoo = new NameableFoo()
// const nameableFoo: Foo & INameable
const fooName = nameableFoo.name
// const fooName: string | undefined
希望其中之一能有所帮助。祝你好运!