Reputation: 117
I've got a function (func) on a class (MyClass) with an optional parameter. The type of the optional parameter (MyInterface) has only optional properties.
I expected a compiler error when I call foo with a primitive like a number. But thats not the case. Why is it like that? And is there a way to tell the type system to mark that as an error?
interface MyInterface {
foo?: string
}
class MyClass {
func(b?: MyInterface) : void {}
}
let c = new MyClass();
c.func();
c.func({ foo: 'bar' });
c.func({ foo: 30 }); // compiler error: OK
c.func({});
c.func(60); // No compiler error: Not what I expect
Upvotes: 4
Views: 1991
Reputation: 18373
Let's introduce some dirty console.log-debugging:
interface MyInterface {
foo?: string
}
class MyClass {
func(b?: MyInterface): void {
console.log(`b:${b}`);
if (b != undefined) {
console.log(`b.foo:${b.foo}`);
}
}
}
let c = new MyClass();
c.func();
c.func({ foo: 'bar' });
c.func({ foo: 30 }); // compiler error: OK
c.func({});
c.func(60); // No compiler error: Not what I expect
Results are:
b:undefined
b:[object Object]
b.foo:bar
b:[object Object]
b.foo:30
b:[object Object]
b.foo:undefined
b:60
b.foo:undefined
Let's focus on the last two results.
MyInterface
has only foo
parameter, which is moreover optional. So actually anything is of type MyInterface
. That's why parameter b
has value 60. b
is in this case of type MyInterface
without optional foo
member.
If you remove optional operator from foo
member then compiler will throw the exception. It will do the same if you add additional, non optional parameter to MyInterface
.
Maybe it seems counter-intuitive but it's not. In the form you presented, the MyInterface
doesn't define anything. You ask compiler to guard input to have foo
parameter... or not have it. So why should it check if input is object
?
Upvotes: 0
Reputation: 174957
The reason this happens is that number
is compatible with {}
. (for example, imagine an argument of type {toFixed: (n: number) => string}
, that too, is compatible with number
).
You can also think about it this way: you can do anything with a number, that you could with a {foo?: string}
.
Upvotes: 2