¿Por qué se permite escribir pato para las clases en TypeScript?

Parece que en TypeScript está absolutamente bien (desde la perspectiva del compilador) tener ese código:

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());

Pero al mismo tiempo esperaría unerror de compilación, porqueVehicle yTask No tengo nada en común.

Ycuerdo los usos se pueden implementar a través de la definición explícita de la interfaz:

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());

... o un objeto principal común:

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());

Y sí, para JavaScript está absolutamente bien tener ese comportamiento, porque no hay clases ni compilador (solo azúcar sintáctico) y la tipificación de pato es natural para el lenguaje. Pero TypeScript intenta introducir comprobaciones estáticas, clases, interfaces, etc. Sin embargo, el tipeo de pato para instancias de clase parece bastante confuso y propenso a errores, en mi opinión.

Respuestas a la pregunta(1)

Su respuesta a la pregunta