MichaelAttard
MichaelAttard

Reputation: 2158

Typescript union type inference

How would I achieve type inference in the following case:

type a = {
    foo: number;
    bar: string;
}

type b = {
    foo: string;
}

let baz: a | b;

if (baz.foo === 5) {
    baz.bar = "abc"; // baz type is still a | b, should be a
}

Upvotes: 1

Views: 177

Answers (2)

Duncan Lukkenaer
Duncan Lukkenaer

Reputation: 13954

Apparently types cannot be inferred from the types of their properties, so you will need to define a type guard:

type a = {
    foo: number;
    bar: string;
}

type b = {
    foo: string;
}

let baz: a | b;

function isA(x: a | b): x is a {
    return typeof x.foo === 'number';
}

if (isA(baz) && baz.foo === 5) {
    baz.bar = "123";
}

The isA type guard will tell TypeScript that you have checked bazs type yourself. Below is another way to achieve this with casts, but here you still need to cast baz for every usage which is probably not the best way to do this.

if ((baz as a).foo === 5) {
    (baz as a).z = "123";
}

More information about type guards can be found in the TypeScript docs.

Upvotes: 2

Matthew Layton
Matthew Layton

Reputation: 42270

baz type is still a | b, should be a

Actually what the TypeScript compiler does is restricts property access of all unified types (a | b) to properties that exist on all of them, thus, baz.bar does not even compile because bar does not exist on type b.

Upvotes: 0

Related Questions