Kir Kir - 11 days ago 5
TypeScript Question

Typescript typeguards for generics not enforced

interface Foo {
bar() : Promise<string>;
}

class MyFoo implements Foo {
bar() : string {
return "";
}
}

class MyFoo2 implements Foo {
bar() : Promise<number> {
return new Promise<number>(null);
}
}


Shouldn't each of the two implementations above cause an error?


  • MyFoo does get an error, because it returns string and not Promise

  • MyFoo2 returns a promise, but of the wrong type, and gets no error -- why?



What I can tell is that TypeScript seems to check the members of the return type and not the declared type. But is there a way to declare this interface in a way that requires the implementations to return the correct type?

edit: It seems that because the es6 interface
Promise
is defined with members like
then() : Promise<T>
, but nothing like
foo(): T
, the type checking doesn't work. If I simulate this with my custom generic interface, it will properly error if the interface contains a member of type
T
, but not of a generic of type
T

Answer

This is a bug in the current stable version of TypeScript.

Sources:

It has already been fixed and will be included in a future version (2.1).

I tried it myself too:

D:\Practice\TypeScript\ts-test>npm install -g typescript
C:\Users\dezsi\AppData\Roaming\npm\tsc -> C:\Users\dezsi\AppData\Roaming\npm\node_modules\typescript\bin\tsc
C:\Users\dezsi\AppData\Roaming\npm\tsserver -> C:\Users\dezsi\AppData\Roaming\npm\node_modules\typescript\bin\tsserver
C:\Users\dezsi\AppData\Roaming\npm
└── typescript@2.0.10


D:\Practice\TypeScript\ts-test>C:\Users\dezsi\AppData\Roaming\npm\tsc.cmd --version
Version 2.0.10

D:\Practice\TypeScript\ts-test>C:\Users\dezsi\AppData\Roaming\npm\tsc.cmd --target ES6 app.ts

D:\Practice\TypeScript\ts-test>npm install -g typescript@next
C:\Users\dezsi\AppData\Roaming\npm\tsc -> C:\Users\dezsi\AppData\Roaming\npm\node_modules\typescript\bin\tsc
C:\Users\dezsi\AppData\Roaming\npm\tsserver -> C:\Users\dezsi\AppData\Roaming\npm\node_modules\typescript\bin\tsserver
C:\Users\dezsi\AppData\Roaming\npm
└── typescript@2.2.0-dev.20161122



D:\Practice\TypeScript\ts-test>C:\Users\dezsi\AppData\Roaming\npm\tsc.cmd --version
Version 2.2.0-dev.20161122

D:\Practice\TypeScript\ts-test>C:\Users\dezsi\AppData\Roaming\npm\tsc.cmd --target ES6 app.ts
app.ts(5,7): error TS2420: Class 'MyFoo2' incorrectly implements interface 'Foo'.
  Types of property 'bar' are incompatible.
    Type '() => Promise<string>' is not assignable to type '() => Promise<number>'.
      Type 'Promise<string>' is not assignable to type 'Promise<number>'.
        Type 'string' is not assignable to type 'number'.

Here you can see that trying with version 2.0.10 doesn't give me an error, while the latest 2.2.0-dev.20161122 correctly reports Type 'string' is not assignable to type 'number'.

Comments