en.wikipedia.org/wiki/Nominal_type_system
е, в TypeScript абсолютно нормально (с точки зрения компилятора) иметь такой код:
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());
Но в то же время я ожидалошибка компиляции, потому чтоVehicle
а такжеTask
не имеет ничего общего.
А такжездравомыслящий использование может быть реализовано через явное определение интерфейса:
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());
... или общий родительский объект:
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 пытается ввести статические проверки, классы, интерфейсы и т. Д. Однако, по моему мнению, типизация утки для экземпляров классов выглядит довольно запутанно и подвержена ошибкам.