microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.33k stars 12.4k forks source link

Interface extension error(by specifying some existed type) #14671

Closed senyaak closed 7 years ago

senyaak commented 7 years ago

TypeScript Version: 2.2.1

Code

// this does not work
interface a {
  foo(name: string): void;
}

interface b extends a {
  foo(name: 'bar'): void;
}

// this works
interface a {
  foo(name: string): void;
}

interface b extends a {
  foo(name: 'bar'): void;
  foo(name: string): void;
}

Expected behavior: " this does not work" - part should compile without errors Actual behavior: The compiler throw an error:

error TS2430: Interface 'b' incorrectly extends interface 'a'. Types of property 'foo' are incompatible. Type '(name: "bar") => void' is not assignable to type '(name: string) => void'. Type '(name: "bar") => void' provides no match for the signature '(name: string): void'

senyaak commented 7 years ago

I have tried some more cases and got a questin:


var b: B;

interface A {
  foo(name: string, callback: () => void);
}
interface B extends A {
  foo(name: 'John', callback: (age: number) => void); //foo type 1
  foo(name: string, callback: () => void); //foo type 2
}

b.foo("John",(a) => {});

in this case b.foo has type "foo type 2" I think the compiler should throw an error that the function ()=>void is not assignable to type (age: number) => void, shouldn't it?

sandersn commented 7 years ago

@senyaak I can't repro your error on the playground

Is there some combination of tsconfig options that I am missing?

Regarding your second question, a function with zero parameters is assignable to a function with one parameter because the zero-param function with just ignore the one argument:

type Nullary = () => void;
type Unary = (a: string) => void;
let n: Nullary;
let u: Unary;
/// not ok ///
n = u // not ok
n() // u expected an argument!
/// ok ///
u = n
u(12) // ok, n will ignore its argument

This is important to make map usable, since it passes 3 arguments to its callback, but the callback is almost always written with only 1 parameter.

senyaak commented 7 years ago

@sandersn Thank you for your answer. Have only atom settings: "compileOnSave": false, "buildOnSave": false, "noEmitOnError": false,

in my tsconfig

This is important to make map usable, since it passes 3 arguments to its callback, but the callback is almost always written with only 1 parameter.

I think it's a broken behavior, the code isn't type save now.. The optional parameters should be used in this case Update: Besides I think the string literal types should have higher priority than string types, otherwise it makes no sense if you have case like this...

senyaak commented 7 years ago

Tried on the other pc - it works now Oo Can be closed.

sandersn commented 7 years ago

Thanks for checking.

Here's the FAQ entry on why functions with fewer parmaeters are assignable to functions with more: https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-functions-with-fewer-parameters-assignable-to-functions-that-take-more-parameters