对一个具有枚举静态属性的类进行子类化,并保留类型信息。
对一个具有枚举静态属性的类进行子类化,并保留类型信息。
问题来源:将枚举定义为类的静态属性
在下面的代码中,我们有一个名为Box的类,其中定义了一个Color枚举属性,可以使用Box.Color
引用该类型。
class Box { constructor(private color: Box.Color) {} } namespace Box { export enum Color { RED, GREEN, BLUE, } } function createBox (color: Box.Color): Box { return new Box(color); } const box = createBox(Box.Color.RED); console.log(box); // { color: 0 }
我的问题是,当我尝试对Box
进行子类化时,Color
属性将会继承(在JavaScript中),但类型信息在TypeScript中不会继承。
class SmallBox extends Box { } function createSmallBox (color: SmallBox.Color): SmallBox { // ^ Error return new SmallBox(color); } const box = createSmallBox(SmallBox.Color.RED); // ^ Works console.log(box);
这在JavaScript中是可行的,因为SmallBox
继承了Box
的静态Color
属性。然而,在TypeScript中不起作用,因为类型信息丢失了。是否有一种方法可以在保留类型信息的同时实现相同的效果?我正在寻找一种通用的方式,可以将Box的所有类型信息应用于SmallBox,而无需创建一个新的SmallBox
命名空间并手动列出每个类型。
编辑:我已经能够提出以下解决方案,它需要一个额外的命名空间来传递信息。不过,如果可能的话,我希望摆脱额外的子命名空间。
class Box { constructor(private color: Box.Subtypes.Color) {} } namespace Box { export namespace Subtypes { export enum Color { RED, GREEN, BLUE, } } } function createBox (color: Box.Subtypes.Color): Box { return new Box(color); } class SmallBox extends Box { } namespace SmallBox { export import Subtypes = Box.Subtypes; } function createSmallBox (color: SmallBox.Subtypes.Color): SmallBox { // ^ Works return new SmallBox(color); } const box = createSmallBox(SmallBox.Subtypes.Color.RED); // ^ Works console.log(box);
问题的原因是希望在子类中继承父类的枚举静态属性,并保持类型信息。当前的解决方法是通过在基类上定义一个具有所需枚举值的对象,并使用as const
(一个const
断言)来创建一个类型别名来表示这些枚举值的联合(在下面的示例中为BoxColor
)。使用这种方法,一切都更简单:没有命名空间合并,没有枚举代码生成等。
解决方法的代码示例:
type Values<T> = T[keyof T];
export type BoxColor = Values<typeof Box.Color>; // 0 | 1 | 2
class Box {
static readonly Color = {
RED: 0,
GREEN: 1,
BLUE: 2,
} as const;
constructor(private color: BoxColor) {}
}
function createBox (color: BoxColor): Box {
return new Box(color);
}
const box = createBox(Box.Color.RED);
console.log(box); // { color: 0 }
export class SmallBox extends Box {}
export function createSmallBox (color: BoxColor): SmallBox {
return new SmallBox(color);
}
const smallBox = createSmallBox(SmallBox.Color.RED);
console.log(smallBox); // { color: 0 }
如果消费者需要访问该类型,他们可以在值导出的同时导入它:
import {type BoxColor, createSmallBox} from './the-module-above.mts';
然而,这种解决方法并不能解决问题。虽然可以导出多个内容,包括类型,然后导入这些内容并使用它们。但问题是我想仅导入SmallBox
并获得所有与它相关的内容:包括SmallBox
类(可以),SmallBox
类型(可以),SmallBox.Color
对象(可以),以及SmallBox.Color
类型(不行)。为什么有一种方法可以让值和类型重叠,但没有一种方法可以让对象属性的值和类型重叠,并且能够继承,我不确定。
感谢您提供有关const断言的信息!但如果这些内容是标准,为什么你在问题中没有包含它们呢?