10

I don't understand why type guard doesn't work in the example below...

When we have these interfaces,

interface ParamA {
    name: 'A';
    aaa: boolean;
}

interface ParamB {
    name: 'B';
    bbb: number;
}

Good

function func(param: ParamA | ParamB) {
    switch (param.name) {
        case 'A':
            const aaa = param.aaa;
            console.log(aaa); // boolean
            break;
        case 'B':
            const bbb = param.bbb;
            console.log(bbb); // number
            break;
        default:
            break;
    }
}

Bad

function func(param: ParamA | ParamB) {
    const name = param.name; // just rewrite here
    switch (name) {
        case 'A':
            const aaa = param.aaa;
            //                ^^^
            console.log(aaa);
            break;
        case 'B':
            const bbb = param.bbb;
            //                ^^^
            console.log(bbb);
            break;
        default:
            break;
    }
}

Compiler throws errors like Property 'aaa' does not exist on type 'ParamB'. I do not think there should be a difference in behaviors whether I can put it in a variable.

The version of TypeScript using is 2.8.3.

Can anyone explain this?

2 Answers 2

5

Update 2021-08:

Typescript 4.4 got smarter and your example work out of the box :-)

Old answer

Assigning the property to a variable looses the connection to the object. This would be very hard to follow for the compiler as you could change the string and the object variable independently:

var param: ParamA | ParamB;
param = someParamA;
const name = param.name;
param = someParamB;
switch (name) { // boom

So if you know for sure that you have not changed the variable you can use the type assertion but i would not do that for maintenance reason.

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

2 Comments

Is this true? if so i would have expected something like this: typescriptlang.org/play?#code/… to not work
I have no idea what you want to say with the example. Why should shouldBeBooleanButNot be boolean? It is clear the type of the sub object. Did you linked a wrong example? ParamB is not used at all.
3

switch statement serves as type guard in 'good' snippet and doesn't do that in 'bad' one.

I do not think there should be a difference in behaviors whether I can put it in a variable.

There's no difference in behaviour, there's a difference in how TypeScript is able to analyze this code. Since the code is statically analyzed, the ways how param type can be narrowed are limited.

In order for param to be narrowed down to ParamA or ParamB it should be mentioned in type guard. Since it wasn't but name variable was, param won't be narrowed down, its type will need to be asserted in this case:

...
switch (name) {
    case 'A':
        const aaa = (<ParamA>param).aaa;
...

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.