Search code examples
typescript

Is it possible to make union of global scope in TypeScript?


If you create a union type and then use if statement to identify it's type TypeScript will let you use properties & functions specific to this type:

type A = {
    type: "A",
    func(): void
};

type B = {
    type: "B"
};

type Union = A | B;

const test: Union = ...;

test.func(); // Error: func does not exist on type B

if (test.type === "A")
    test.func(); // Works fine

Is it possible to make this union globally, by making union of two scopes? Something like this would be very nice:

declare global {
    environment: "A",
    funcA(): void
} | {
    environment: "B",
    funcB(): void
}

funcA(); // Doesn't work (environment could be B, and B doesn't have funcA)

if (environment === "A")
    funcA(); // Works (environment is A)
else
    funcB(); // Works (environment is B)

I tried searching for this, but couldn't find anything that meets my needs. Is there any specific syntax or any workarounds?


Solution

  • One approach is to use a destructured discriminated union, where you assign the environment, funcA, and funcB variables as destructured from an object of a discriminated union type. Here's an example using a tuple:

    declare const
        [environment, funcA, funcB]:
            ["A", () => void, undefined] |
            ["B", undefined, () => void];
    
    funcA(); // error!
    if (environment === "A") {
        funcA(); // okay
    } else {
        funcB(); // okay
    }
    

    That works because environment is considered the discriminant property of a discriminated union. When you check it, then funcA and funcB will be narrowed accordingly.

    Playground link to code