TypeScript is a natural extension of JavaScript that’s used in many projects in place of JavaScript.
However, not everyone knows how it actually works.
In this article, we’ll look at the use of the never
type, unknown
type, and removing null
from a union.
Never Type
TypeScript provides us with the never
type for situations where the type guard has dealt with all the possible types for a value.
Once all the possible types have been handled then the compiler will only allow a value to be assigned to the never
type.
For instance, if we have a switch
statement:
const getTax = (price: number, format: boolean): string | number => {
if (typeof price !== "number") {
return 0;
}
if (format) {
return (price * 0.2).toFixed(2) as string;
}
return (price * 0.2) as number;
};
let tax = getTax(100, false);
switch (typeof tax) {
case "number":
console.log(`Number: ${tax.toFixed(2)}`);
break;
case "string":
console.log(tax);
break;
default:
let value: never = tax;
console.log(`Unexpected type for value: ${value}`);
}
Then we assign the value for the default
case to a variable with a never
type since we handled the string and number in the previous cases.
Using the unknown Type
The unknown
type is a safer alternative to any
.
It indicates that we don’t know the type of the value.
We can assign things to an unknown
type.
For instance, we can write:
let tax: unknown = getTax(100, false);
tax
can’t be assigned to a variable of another type without a type assertion.
Nullable Types
null
and undefined
types aren’t in the TypeScript type system.
However, we can create nullable versions of variables by using nullable types.
For instance, we can write:
const getTax = (price: number, format: boolean): string | number | null => {
if (typeof price !== "number") {
return null;
}
if (format) {
return (price * 0.2).toFixed(2) as string;
}
return (price * 0.2) as number;
};
Now we can return null
in addition to number
or string
.
For parameter, we can write:
const getTax = (price?: number, format: boolean): string | number | null => {
if (typeof price !== "number") {
return null;
}
if (format) {
return (price * 0.2).toFixed(2) as string;
}
return (price * 0.2) as number;
};
We put a ?
beside the parameter name so that we indicate that it might be null
or undefined
.
Restricting Nullable Assignments
We can restrict the use of null
or undefined
by enabling the strictNullChecks
compiler setting.
If we set it to true
, then we can’t assign null
to something that’s not the type of variable that has other data types specified.
If we have that on, then we’ll get ‘Type ‘null’ is not assignable to type ‘string | number’.ts(2322)’.
So we’ve to add null
to the type union as we have before.
Removing null from a Union
We can remove null
from a union type with a non-null assertion.
For instance, if we write:
let tax: string | number = getTax(100, false)!;
Then we make sure that we don’t have null
returned and assigned to tax
.
We can also remove null
s with type guards.
For instance, we can write:
if (tax !== null) {
//..
}
to do null checks before proceeding.
Definite Assignment Assertion
If strictNullChecks
option is enabled, the compiler will report an error if a variable is used before being assigned a value.
For instance, we can add null
to the union type of the tax
variable, and then assert it later.
We write:
let tax: string | number | null = getTax(100, false);
Then we can narrow it to the type we want in other statements with as
or brackets.
Conclusion
The never
type is used when we handled all the other types in our conditional statements.
unknown
is a safer alternative to any
. Variables of unknown
type can’t be assigned to other variables.
There are various ways to remove a type from a union.