不简单:从函数中返回一个类
不就 这样 么?
export function test() {
class Inner {}
return Inner;
结果当然是报错了。在这里
test()
没有注解返回值的类型,那么 TypeScript 自然而然会去推测返回值类型,而返回值是函数内部的
不公开
类型
Inner
,TypeScript 无法在函数外部表示函数内部的类型。
那么要解决的核心问题就出现了: 如何避免在函数的返回值中涉及函数内部的类型?
解决方案
匿名类
Typescript 会将匿名类的类型表示成一个又臭又长的
{}
匿名类型,因不涉及函数内部的类型了,自然就不报错了:
export function test() {
return class Anonymous {
method() {}
优点
- 代码一目了然,写起来方便
- 适用大部分简单情况
缺点
- 无法声明私有成员、保护乘员
- 无法使用装饰器
断言返回值类型
通过将返回值从自动推测出的内部类型
Inner
断言至一个等价的匿名
{}
类型,就可以完美避免在返回值类型中出现函数内部的类型:
export function test() {
class Inner {
static p = 3;
constructor(private property: string) {}
method() {}
type InstanceType = {
[K in keyof Inner]: Inner[K];
type StaticMembers = {
[K in Exclude<keyof typeof Inner, "prototype">]: typeof Inner[K];
} & { prototype: InstanceType };
return Inner as {
new (...args: ConstructorParameters<typeof Inner>): InstanceType;
} & StaticMembers;
优点
- 支持私有成员、保护成员、装饰器
缺点
- 代码繁琐,不易理解
- 子类无法访问保护成员
注解返回值类型
通过使用外部类型标注函数的返回值来避免涉及函数内部类型:
export interface Instance {
method(): void;
export interface Constructor {
new (property: string): Instance;
prototype: Instance;
p: number;
export function test(): Constructor {
class Inner {
static p = 3;
constructor(private property: string) {}
method() {}
return Inner;
优点
- 代码清晰、易于理解
- 支持私有成员、保护成员、装饰器
缺点
- 代码大量重复
- 子类无法访问保护成员
拓展:Mixins
在翻某库的代码时,发现了 这么一种很玄学的方法 :
export function test<T extends { new (...args: any[]): any }>(baseType: T) {
class Inner extends baseType {
static staticProperty = "aaaa";
constructor(...args: any[]) {
super();