typescript - 何时使用可区分联合与实现接口的类
问题描述
我有这样的代码:
interface Node{
value: number;
}
class Parent implements Node{
children: Node[] = [];
value: number = 0;
}
class Leaf implements Node{
value: number = 0;
}
function test(a:Node) : void {
if(a instanceof Leaf)
console.log("Leaf")
else
console.log("Parent")
}
查看https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions,似乎实现这一目标的另一种方式是
type Parent = {kind: "Parent", value:number, children:(A|B)[]}
type Leaf = {kind: "Leaf", value:number}
type Node = Parent | Leaf
function test(a:Node) :void {
if(a.kind === "Leaf")
console.log("yes")
else
console.log("no")
}
现在,我对使用什么感到困惑。到目前为止,我使用的所有其他语言都只有其中一个选项 - 这里是 typescript 两者都有。除了方法 1 有一个构造函数之外,方法 2 完全被转译了,这里真正的区别是什么?在代码库中最好看到哪种方法?
如您所见,该功能使我们可以轻松地遍历树。当然,我也可以只有一个类型/类并将子项设置为 [] 那里,但是类型与类的问题被重复了。有人告诉我,不同的课程对性能更友好。
解决方案
可区分联合和接口之间的主要区别在于接口对扩展是开放的,但联合不是。
也就是说,给定一个接口,任何人都可以添加该接口的新实现。相反,向联合中添加其他类型需要更改该联合。因此,如果预先知道可能的类型集,则联合是优越的,而接口允许稍后扩展可能的类型集。
至于类和接口之间的选择,类有一个原型,这允许它们继承行为(甚至状态),但会使类型更难通过网络发送(JSON 没有原型的概念......)。因此,如果您从原型中受益,那么类会受到青睐,而接口(或联合)则更适合与其他进程交换数据。
不过,在您的情况下,所有这些都是一个红鲱鱼,因为我认为用不同类型表示树中的不同节点没有任何好处。您的行为没有差异,数据差异最容易通过空列表建模。也就是说,我只是这样做:
interface Node {
value: number;
children: node[];
}
这使代码变得更简单。假设您要向叶子添加一个新子节点。在您的情况下,您需要执行以下操作:
addChild(value: number) {
const leaf = new Leaf();
leaf.value = value;
const newSelf = new Parent();
newSelf.value = this.value;
newSelf.children = [leaf];
this.parent.children = this.parent.children.map(child => child == this ? newSelf : child);
}
而我只会这样做:
addChild(value: number) {
this.children.push({
value,
children: []
});
}
有人告诉我,不同的课程对性能更友好。
差异非常小(例如,大约 0.000000001 秒)。你可能有更紧迫的担忧。
推荐阅读
- javascript - 过滤器不适用于第三个子级别(嵌套级别)
- c++ - 如何从控制台启动可执行文件并使用 Qt 读取输出
- python - 如何使用python遍历二进制块并在文件末尾停止?
- php - Laravel 5.4 - 如何使用 EDI 供应商库
- angular - Angular 7+,从父组件调用子组件的方法好吗?
- azure - 将资源组从开发公司转移到客户公司
- java - 如何为 selenium +TestNG+java 项目设置魅力?
- javascript - 将 jQuery 搜索限制为特定容器,例如 h 和 p 标签
- javascript - 下拉固定位置和格式不起作用
- android - Play 商店报告“您的设备与此版本不兼容”但它通过 adb 安装在 onePlus 上就好了