Typescript optional parameter type check
I have a function (func) for a class (MyClass) with an optional parameter. The optional parameter type (MyInterface) only has additional properties.
I was expecting a compiler error when I call foo with primitive like a number. But it's not that. Why is that? And is there a way to tell the type system to flag this 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
source to share
The reason for this is that it is number
compatible with {}
. (for example, imagine a type argument {toFixed: (n: number) => string}
that is also compatible with number
).
You can also think of it this way: you can do whatever you want with a number that you could use {foo?: string}
.
source to share
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:
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 a parameter foo
, which is also optional. So everything actually has a type MyInterface
. Therefore, the parameter b
is set to 60. b
In this case, it is of type MyInterface
without an optional member foo
.
If you remove the optional operator from the member foo
, then the compiler will throw an exception. It will do the same if you add an additional optional parameter to MyInterface
.
It might sound intuitive, but it isn't. In the presented form, MyInterface
it defines nothing. You are asking the compiler to protect the input to have a parameter foo
... or not to have it. So why should it check if there is an input object
?
source to share