Home > Software engineering >  Why is the type not inferred to be a union, but just one of the types?
Why is the type not inferred to be a union, but just one of the types?

Time:09-03

I have a class:

class Cancelled {
    static cancelled = new Cancelled()
    static from<T>(v: T | undefined) {
        return v ?? this.cancelled
    }
}

Why does VSCode infer the return type of Cancelled.from as only Cancelled instead of T | Cancelled?

CodePudding user response:

Why Vscode infers the type of the result of the function Cancelled.from as only Cencelled instead of T | Cancelled?

Because at the moment, Cancelled doesn't define any non-static properties. That means it's compatible with almost anything. In the following code, the only lines that complain are the null and undefined:

const a: Cancelled = true;
const b: Cancelled = {};
const c: Cancelled = "hi";
const d: Cancelled = 3;
const e: Cancelled = new Date();
const f: Cancelled = () => {};
const g: Cancelled = Symbol('foo');
const h: Cancelled = null; // Error
const i: Cancelled = undefined; // Error

But your code excludes null and undefined, so we can ignore them. What we're left with is that Cancelled is a broader type than NonNullable<T>. Everything that is a NonNullable<T> is also a Cancelled, so saying Cancelled | NonNullable<T> is redundant. VS code shows the simpler type.

Playground Link

As soon as you add even one property to Cancelled, this is no longer the case, and the return type will be inferred to be Cancelled | NonNullable<T>.

class Cancelled {
    static cancelled = new Cancelled()
    static from<T>(v: T | undefined) {
        return v ?? this.cancelled
    }

    foo: string = 'bar'
}

Playground link

  • Related