TypeScript 4.0 comes with lots of new features to make JavaScript development easier.
In this article, we’ll look at the best features of TypeScript 4.
Variadic Tuples
TypeScript 4.0 comes with data types for tuples with a variable number of elements.
We can use the spread operator to create a type with the elements we want in our tuple.
For example, we write:
type Strings = [string, string];
type Numbers = number[];
type Unbounded = [...Strings, ...Numbers, boolean];
to create an Unbounded
data type to add a tuple type with strings, numbers, and booleans.
The inference process is also automatic so that if we have 2 strings, numbers, and a boolean in the same order, TypeScript will infer the tuple as having the Unbounded
type.
Labeled Tuple Elements
We can label tuple elements.
For example, we can write:
type Range = [start: number, end: number];
to restrict args
to have a string and a number.
We can also write:
type Foo = [first: number, second?: string, ...rest: any[]];
to have rest entries in our tuple.
If our tuple has type Foo
, then the tuple starts with a number and a string.
Then the rest of the entries can be anything.
Labels don’t require us to name our variables differently when destructuring.
For example, if we have:
function foo(x: [first: string, second: number]) {
const [a, b] = x;
}
then we can name then destructured variables anything we want.
Class Property Inference from Constructors
TypeScript 4.0 can infer class properties’ types from the constructor.
For example, if we have:
class Square {
area;
length;
constructor(length: number) {
this.length = length;
this.area = length ** 2;
}
}
then TypeScript 4.0 knows that this.length
and this.area
are numbers automatically.
If there’s a chance that the value of them are undefined
, then the TypeScript compiler will notify us of that.
So if we have:
class Square {
length;
constructor(length: number) {
if (Math.random()) {
this.length = length;
}
}
get area() {
return this.length ** 2;
}
}
then we’ll know that this.length
may be undefined
.
We would need a type assertion even if we know that it’s always defined.
For example, we can write:
class Square {
length!: number;
constructor(length: number) {
this.initialize(length);
}
initialize(length: number) {
this.length = length;
}
get area() {
return this.length ** 2;
}
}
We set length
to be non-null with the !
symbol and set its type explicitly to number
to make sure this.length
is always a number.
Short-Circuiting Assignment Operators
TypeScript 4.0 has new assignment operator shorthands.
Now we write the logical AND, logical OR, and bullish coalescing operators with shorthands.
For example, instead of writing:
a = a && b;
a = a || b;
a = a ?? b;
We write:
a &&= b;
a ||= b;
a ??= b;
unknown
on catch
Clause Bindings
We can specify the binding variable of the catch
clause to have an unknown
type instead of an any
type.
With the unknown
type, we have to cast the exception object explicitly before we can do things with it.
For example, we can write:
try {
// ...
} catch (e: unknown) {
if (typeof e === "string") {
console.log(e.toUpperCase());
}
}
Then we check if e
is a string before we call toUpperCase
on it.
Conclusion
TypeScript 4.0 comes with many new language features that we can use to check for types.
Type inference is also improved.