What & Why
Setup
Type Annotations
Type System
ConfigurationLibraries
For Potential Contributors
Index

Union Types

Edit

Sometimes you need more than one type or need to concrete values from any of existed type. A simple example when you need values from two different types is repeat function, which is waiting argument as number or string and repeat given argument n times:

Playground
function repeat(target, times) {
if (typeof target === "number") {
return target ** times;
}
return target.repeat(times);
}

You can define types like this:

Playground
function repeat(target: unknown, times: number): unknown {
if (typeof target === "number") {
return target ** times;
}
// Error: Property "repeat" does not exist in "unknown"
return target.repeat(times);
}

But you will have an Error, because you try to get property from unknown type. You can try to add one more if statement like this:

Playground
function repeat(target, times) {
if (typeof target === "number") {
return target ** times;
}
if (typeof target === "string") {
return target.repeat(times);
}
throw new TypeError(`Expected string or number, got '${typeof target}'.`);
}
const result = repeat(false, 4);

But, if you put a wrong type (not number or string) you will find an error in runtime.

So, the solution is union types. Actually, union types is a union of all possible values for types which will be provided to union operator |. You can define it by declaring sequence of needed types separated by '|':

Playground
let iCanBeAStringOrNumber: string | number = 2;
iCanBeAStringOrNumber = "Hello";
// Error: Type "false" is incompatible with type "number | string"
iCanBeAStringOrNumber = false;

When you defined union type you lost ability to use this type as concrete type.

Playground
const iCanBeAStringOrNumber: string | number = 2;
// Error: Type "number | string" is incompatible with type "number"
const value: number = iCanBeAStringOrNumber;
// Error: Parameter "number | string" is incompatible with type "bigint | number"
iCanBeAStringOrNumber * 4;

With union types repeat function will look like this:

Playground
function repeat(target: string | number, times: number): string | number {
if (typeof target === "number") {
return target ** times;
}
return target.repeat(times);
}
// Error: Type "false" is incompatible with type "number | string"
const result = repeat(false, 4);

And you will see wrong execution in static time (while you are writing code in editor).

Also, union types are usefull when you want to pick only concrete values from some type.

Playground
function createResponse(status: "Success" | "Failed") {
return { status };
}
let response = createResponse("Success");
response = createResponse("Failed");
// Error: Type "'Custom String'" is incompatible with type "'Failed' | 'Success'"
response = createResponse("Custom String");