stefku
stefku

Reputation: 117

typescript optional parameter type check

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

Answers (2)

Arkadiusz Kałkus
Arkadiusz Kałkus

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

Madara's Ghost
Madara's Ghost

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

Related Questions