Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript not enforcing interfaces

Tags:

typescript

Consider the interface CommicBookCharacter

interface CommicBookCharacter {
    name: string;
    fight : (nemisis: CommicBookCharacter) => void;
}

Which may be implemented by both heros and villian. Besides of these characters, there are also civilians

class Civilian{
    constructor(public name: string) {}
}

and here is how a hero could be implemented

class SuperHero implements CommicBookCharacter {
    fight: (villian: Civilian) => void;

     constructor(public name: string) {
        this.fight = (hero)=> {
            alert(this.name + ' is struggling back');
        };
    }
}

Lets create some characters as well

var spiderMan= new SuperHero('Spider Man');
var mj = new Civilian('Mary Jane');

Here is my problem. The civilian class does not implement the ComicBookCharacter interface, but the SuperHero can still implement the fight method with the Civilian argument.

This results in some bad problems:

spiderMan.fight(mj);

As a side note: if I would change the type of villian in the SuperHeru class to, say string, it would give me an compilation error. In my opinion, this is a buggy behavior. SpiderMan should not be able to fight Mary Jane!

like image 684
pardahlman Avatar asked Sep 25 '26 01:09

pardahlman


1 Answers

You are explicitly accepting a Civilian as an argument :

interface ComicBookCharacter {
    name: string;
    fight: (nemisis: ComicBookCharacter) => void;
}

class Civilian{} 

class SuperHero implements ComicBookCharacter {    
    name:string;
    // You explicitly accept Civilian
    fight = (villian: Civilian) => {}; 
}

This interface implementation is allowed since function argument types are bivariant, (as pointed out by Ryan)

PS: Related https://typescript.codeplex.com/workitem/2282 In particular : https://typescript.codeplex.com/workitem/2282#CommentContainer6

like image 140
basarat Avatar answered Sep 27 '26 00:09

basarat