typescript - 在运行时区分泛型类型的可能性的最佳方法是什么?
问题描述
我有一个通用类型,它可以是 6 种可能性之一:
type Attribute<T> = {
name: string;
value: T | null;
};
type StringAttribute = Attribute<string>;
type BoolAttribute = Attribute<boolean>;
type NumberAttribute = Attribute<number>;
type NumberArrayAttribute = Attribute<number[]>;
type PointAttribute = Attribute<Point>;
type PointArrayAttribute = Attribute<Point[]>;
我想在运行时区分这些。在伪代码中:
[..attributes].forEach((attr) => setAttribute(attr, target))
function setAttribute(attr: Attribute<string | boolean | number | number[] | point | point[]>, target: ExtendedElement) {
...
if (isNumberArrayAttribute(attr)) {
target.setNumberArrayAttribute(attr.name, attr.value)
}
...
}
由于无法在正常运行时检查 TypeScript 类型,因此我需要编写一些 JavaScript 代码来模仿 TypeScript 类型。我看到了两种替代解决方案
用户定义的类型保护:
function isNumberArray(val: any): val is number[] {
if (!val.isArray()) {
return false;
}
return val.every((v) => typeof v === "number")
}
function setAttribute(attr: Attribute<string | boolean | number | number[] | point | point[]>, target: ExtendedElement) {
...
if (isNumberArray(attr.value)) {
target.setAttr(attr.name, attr.value)
}
...
}
课程:
class NumberArrayAttribute extends Attribute {
name: string
value: number[]
constructor(name: string, value: number[]) {
this.name = name;
this.value= value;
}
}
function setAttribute(attr: Attribute<string | boolean | number | number[] | point | point[]>, target: ExtendedElement) {
...
if (attr instanceof NumberArrayAttribute) {
target.setNumberArrayAttribute(attr.name, attr.value)
}
...
}
对于我的问题:
- 我无法在用户定义的类型保护方法和类方法之间进行选择。你会说每个的优点是什么?可以说一个比另一个更好或更惯用吗?
- 我的例子有什么可疑之处吗?我是否以错误的方式思考我的问题。你看到我应该使用的其他方法吗?
解决方案
为什么要在函数setAttribute中区分泛型类型?如果这样做,每次添加新属性时,您还需要更新函数setAttribute。
在我看来,每个属性实例都应该知道如何设置“属性”。
考虑这个接口:
interface Attribute<T> {
name: string;
value: T | null;
guard(): boolean;
setAttribute(target: ExtendedElement): void;
};
和这个类:
class NumberArrayAttribute implements Attribute<number[]> {
name: string;
value: number[];
constructor(name: string, value: number[]) {
this.name = name;
this.value= value;
}
public guard(): boolean {
return this.value.isArray() && this.value.every((v) => typeof v === "number");
}
public setAttribute(target: ExtendedElement): void {
target.setAttribute(this.name, this.value)
}
}
该类知道如何执行守卫和setAttribute。现在您可以根据需要创建任意数量的 Attribute<> 类,而无需更改函数 setAttribute:
function setAttribute(){
[...attributes].forEach((attr: Attribute<any>) => {
if (attr.guard()){
attr.setAttribute(target)
}
})
}
推荐阅读
- yii2 - 在 ActiveQuery init() 中获取当前模型别名 Yii2
- sql - 如何将 XML 子节点作为字符串与父属性一起获取?
- python - 功率谱密度-scipy.signal
- javascript - Wicket:弹出内容不会出现在 Chrome 浏览器中
- python - python Sklearn中的SVC分类器支持向量类
- php - 方括号是否使变量为空?
- python - 根据条件复制数据帧的行
- javascript - Uncaught Invariant Violation:超过最大更新深度
- python - 如何使用来自未绑定队列的消息进行多处理
- sql-server - SQL Server 触发器自动填充整个列