Does Typescript use the type annotation for a variable or the specific type of the definition?

Viewed 68

The following code suggests to me that even though I specify a union type for a variable instead of one of the types making up the union, that tsc uses the specific type for a variable.

This code fails to compile with TypeScript 3.9.2:

src/test.ts:49:25 - error TS2339: Property 'language' does not exist on type 'never'.
  The intersection 'CommandNotSelected & SayHelloCommand' was reduced to 'never' because property 'commandType' has conflicting types in some constituents.

35     console.log(command.language);
enum CommandType {
    SAY_HELLO,
    COMMAND_NOT_SELECTED,
}

interface SayHelloCommand {
    commandType: CommandType.SAY_HELLO;
    language: string;
}

interface CommandNotSelected {
    commandType: CommandType.COMMAND_NOT_SELECTED;
}

type Command = SayHelloCommand | CommandNotSelected;

function isSayHelloCommand(c: Command): c is SayHelloCommand {
    return c.commandType === CommandType.SAY_HELLO;
}

let command: Command = {
    commandType: CommandType.COMMAND_NOT_SELECTED,
};

function f() {
    command = {
        commandType: CommandType.SAY_HELLO,
        language: 'foobar',
    };
}

f();

if (isSayHelloCommand(command)) {
    console.log(command.language);
}

I can get this to compile by swapping out the code to

function initialCommand(): Command {
    return {
        commandType: CommandType.COMMAND_NOT_SELECTED,
    };
}
let command = initialCommand();

or

let command: Command = {
    commandType: CommandType.COMMAND_NOT_SELECTED,
} as Command;

I assumed that TypeScript would use Command for the type instead of CommandNotSelected and modify its type as it sees modifications to the command.

0 Answers
Related