4

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

2 Answers 2

2

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}.

Sign up to request clarification or add additional context in comments.

2 Comments

Sounds like duck typing. Does TypeScript does kind of duck typing? In contrast to i.e. java where also an empty class is different from another empty class.
Yes, objects don't need to actually, explicitly implement an interface to belong to that interface. The properties just need to match. Note that with the MyInterface requirement, you won't be able to treat that 60 as a number inside of MyClass.prototype.func.
0

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.