San*_*ord 6 generics typescript
我正在设计一个小型 API。在其中,开发人员定义一个类和一个配置文件,允许他们在我的系统中使用它。
下面是我的代码的简化:
abstract class Box<T> {
constructor(protected initialValue: T) {}
public abstract getDefaultThing(): T;
}
type BoxType = typeof Box;
interface Config {
boxType: BoxType;
initialValue: any;
}
function loadConfig(config: Config) {
// Need to "as any" this so TSC doesn't complain about abstract class
return new (config.boxType as any)(config.initialValue);
}
Run Code Online (Sandbox Code Playgroud)
Box这里我定义了带有泛型参数的抽象类T。我还提供了一个用于编写配置对象的接口,该对象需要对可实例化 Box 类的引用以及初始值。最后是一个小实现函数,它通过使用 value 创建 Box 的新实例来加载配置initialValue。
一个简单的用法如下:
class MyBox extends Box<string> {
public getDefaultThing(): any {
return `${this.initialValue} world`;
}
}
const config: Config = {
boxType: MyBox,
initialValue: "hello",
};
const loaded = loadConfig(config);
console.log(loaded.getDefaultThing()); // prints "hello world"
Run Code Online (Sandbox Code Playgroud)
这已经不起作用了 - boxTypeinconfig有一个错误,因为MyBox它比 更窄Box。没关系,我真正想做的是重新定义我的Config接口以进行类型检查initialValue和BoxType:
type BoxType<T> = typeof Box<T>;
interface Config<T> {
boxType: BoxType<T>;
initialValue: T;
}
Run Code Online (Sandbox Code Playgroud)
这不起作用...根本... Box已经是一种类型,并且不能在没有实例化的情况下接受泛型。我知道在某种程度上我正在混合值和类型,但是有没有办法让属性成为对可实例化泛型类的引用,并将其范围缩小到某个泛型类型?
如果您不使用typeof Box而是键入接受并返回BoxType<T>一个构造函数签名,那么这一切都会很好地解决TBox<T>
abstract class Box<T> {
constructor(public initialValue: T) {}
public abstract getDefaultThing(): T;
}
type BoxType<T> = new (initialValue: T) => Box<T>;
interface Config<T> {
boxType: BoxType<T>;
initialValue: any;
}
function loadConfig<T>(config: Config<T>) {
return new config.boxType(config.initialValue); // no cast
}
class MyBox extends Box<string> {
public getDefaultThing(): string { // there was a typo here this was any
return `${this.initialValue} world`;
}
}
const config = { // no explcit type needed
boxType: MyBox,
initialValue: "hello",
};
const loaded = loadConfig(config); // loaded is Box<string>
console.log(loaded.getDefaultThing()); // prints "hello world"
Run Code Online (Sandbox Code Playgroud)
如果您想loadConfig返回派生类型而不仅仅是抽象类型(即MyBox不是 )Box<string>。您需要一个额外的泛型参数:
abstract class Box<T> {
constructor(public initialValue: T) {}
public abstract getDefaultThing(): T;
}
type BoxType<T, TBox extends Box<T>> = new (initialValue: T) => TBox;
interface Config<T, TBox extends Box<T>> {
boxType: BoxType<T, TBox>;
initialValue: any;
}
function loadConfig<T, TBox extends Box<T>>(config: Config<T, TBox>) {
return new config.boxType(config.initialValue); // no cast
}
class MyBox extends Box<string> {
public getDefaultThing(): string { // there was a typo here this was any
return `${this.initialValue} world`;
}
}
const config = { // no explcit type needed
boxType: MyBox,
initialValue: "hello",
};
const loaded = loadConfig(config); // loaded is MyBox
console.log(loaded.getDefaultThing()); // prints "hello world"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3140 次 |
| 最近记录: |