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:
function repeat(target, times) {if (typeof target === "number") {return target ** times;}return target.repeat(times);}
You can define types like this:
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:
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 '|':
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.
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:
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.
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");