为什么TypeScript中的类允许使用duck typing [英] Why duck typing is allowed for classes in TypeScript

查看:110
本文介绍了为什么TypeScript中的类允许使用duck typing的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在TypeScript中看起来绝对没问题(从编译器的角度来看)有这样的代码:

Looks like in TypeScript it's absolutely fine (from the compiler perspective) to have such code:

class Vehicle {
    public run(): void { console.log('Vehicle.run'); }
}

class Task {
    public run(): void { console.log('Task.run'); }
}

function runTask(t: Task) {
    t.run();
}

runTask(new Task());
runTask(new Vehicle());

但与此同时我会发现编译错误,因为车辆任务没有任何共同点。

But at the same time I would expect a compilation error, because Vehicle and Task don't have anything in common.

sane 用法可以通过显式接口定义实现:

And sane usages can be implemented via explicit interface definition:

interface Runnable {
    run(): void;
}

class Vehicle implements Runnable {
    public run(): void { console.log('Vehicle.run'); }
}

class Task implements Runnable {
    public run(): void { console.log('Task.run'); }
}

function runRunnable(r: Runnable) {
    r.run();
}

runRunnable(new Task());
runRunnable(new Vehicle());

...或一个共同的父对象:

... or a common parent object:

class Entity {
    abstract run(): void;
}

class Vehicle extends Entity {
    public run(): void { console.log('Vehicle.run'); }
}

class Task extends Entity {
    public run(): void { console.log('Task.run'); }
}

function runEntity(e: Entity) {
    e.run();
}

runEntity(new Task());
runEntity(new Vehicle());

是的,对于JavaScript来说,这样的行为绝对没问题,因为没有类,也没有编译器完全(只有语法糖)和鸭子打字是语言的自然。但TypeScript试图引入静态检查,类,接口等。但在我看来,类实例的鸭子打字看起来相当混乱和容易出错。

And yes, for JavaScript it's absolutely fine to have such behaviour, because there is no classes and no compiler at all (only syntactic sugar) and duck typing is natural for the language. But TypeScript tries to introduce static checks, classes, interfaces, etc. However duck typing for class instances looks rather confusing and error-prone, in my opinion.

推荐答案

这是结构打字的工作方式。 Typescript有一个结构类型系统,可以最好地模拟Javscript的工作方式。由于Javascript使用duck typing,因此任何定义契约的对象都可以在任何函数中使用。 Typescript只是尝试在编译时而不是在运行时验证duck typing。

This is the way structural typing works. Typescript has a structural type system to best emulate how Javscript works. Since Javascript uses duck typing, any object that defines the contract can be used in any function. Typescript just tries to validate duck typing at compile time instead of at runtime.

然而,只有在添加私有类时,您的问题才会显示为普通类,即使它们具有相同的结构,类也会变得不兼容:

Your problem will however only manifest for trivial classes, as soon as you add privates, classes become incompatible even if they have the same structure:

class Vehicle {
    private x: string;
    public run(): void { console.log('Vehicle.run'); }
}

class Task {
    private x: string;
    public run(): void { console.log('Task.run'); }
}

function runTask(t: Task) {
    t.run();
}

runTask(new Task());
runTask(new Vehicle()); // Will be a compile time error

此行为还允许您不显式实现接口,例如你的函数可以定义参数内联的接口,任何满足合同的类都是兼容的,即使它们没有显式实现任何接口:

This behavior also allows you to not explicitly implement interfaces, for example you function could define the interface for the parameter inline, and any class that satisfies the contract will be compatible even if they don't explicitly implement any interface:

function runTask(t: {  run(): void }) {
    t.run();
}

runTask(new Task());
runTask(new Vehicle());

就个人而言,来自C#的这一开始看起来很疯狂,但涉及到可扩展性这种类型检查方式允许更大的灵活性,一旦你习惯它,你会看到好处。

On a personal note, coming from C# this was seemed insane at first, but when it comes to extensibility this way of type checking allows for much greater flexibility, once you get used to it you will see the benefits.

这篇关于为什么TypeScript中的类允许使用duck typing的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆