Search code examples
typescriptdowncast

Why does TypeScript allow implicit downcast in method parameters?


Here is the example:

interface Vehicle{
    mass:number
}
interface InspectorClass{
    inspect(v:Vehicle):void
}


class Car implements Vehicle{
    mass = 2000
    wheels = 4
}
class Boat implements Vehicle{
    mass = 3000
    sails = 2
}


// with methods it silently fails:

class BoatInspector implements InspectorClass{
    inspect(v:Boat){ // interface contract silently violated!!!
        console.log(v.mass)
        console.log(v.sails)
    }
}

function runInspection(inspector:InspectorClass, vehicle:Vehicle){
    inspector.inspect(vehicle)
}

let myCar = new Car()
let myBoatInspector = new BoatInspector()
runInspection(myBoatInspector, myCar)


// with functions it checks properly:

type InspectorFunction = (v:Vehicle) => void

const inspectCar:InspectorFunction = function(v:Car){ // TypeScript complains as it should
    console.log(v.mass)
    console.log(v.wheels)
}

TypeScript Playground

The contract of the interface states that an inspect method in an InspectorClass instance has to be able to inspect any kind of Vehicle. Why does TypeScript let me implement a class that actually only accepts Boats without complaining? Is this a bug? Or is it by design for some reason? Or can I enable this with some flag?


Solution

  • The linked duplicate explains the situation. For your code above, the fix is probably to use --strictFunctionTypes and write your method signature as a function-valued-property signature:

    interface InspectorClass{
        inspect: (v:Vehicle) => void
    }
    

    Playground link