If you’re an Angular developer, you’re missing out if you’re not using advanced TypeScript features to help you build better code.
And it’s well worth the effort: TypeScript has some great features that can make you a stronger Angular developer. 💪
BigInt
BigInt lets you represent numbers bigger than 253. This is useful when you need to perform mathematical operations on very large integers. And you can work directly with large integer IDs and high resolution timestamps.
You can create a bigint
primitive in two ways:
const n0 = 1n;
const n1 = new BigInt(1);
bigint
and number
primitives, but they can be compared.NOTE: BigInt support is only available for the
esnext
target.
Numeric Separators _
Numeric separators are great for readability. They don't change how the actual numeric value is interpreted.
// which one is more readable?
const someNumber = 1782540173;
const anotherNumber = 1_782_540_173;
console.log(someNumber === anotherNumber); // true
Keep in mind that you can't begin or end a number with a separator. Also, you can't use two in a row.
Private Fields
TypeScript has the private
keyword that is stripped out during transpilation to JavaScript. If you need private properties at runtime, JavaScript's private fields come to the rescue. Unlike TypeScript's private keyword, private fields are prepended by a # character and are private even at runtime.
If you need private properties at runtime, this is now the way to do it in modern JavaScript.
NOTE: TypeScript will gracefully implement this for older browsers given your target is at least ECMAScript 2015 (ES6).
class Person {
#age = 30;
constructor(public name: string) {}
}
const someone = new Person('John');
console.log(someone.#age); // Property '#age' is not accessible outside class 'Person' because it has a private identifier.
console.log(someone['#age']); // Property '#age' does not exist on type 'Person'
Operators
Nullish Coalescing ??
In JavaScript, nullish refers to a value strictly equal (
===
) tonull
orundefined
A common pattern used in JavaScript when we want a default value is to use the OR operator ||
.
function timeout(callback: Function, milliseconds: number): void {
const wait = milliseconds || 100;
setTimeout(callback, wait);
}
Using the OR operator in this way can cause problems. Since we are dealing with numbers in the example above, then the value 0
will be a valid milliseconds
value.
However, 0
is falsy, so the default value 100
will be assigned to wait
.
It’s important to distinguish between falsy values (false
, 0
, empty string “”
, and null
/undefined
) and nullish values (null
/undefined
). Nullish values are a subset of falsy values.
Nullish coalescing is an operator that returns a default value (the second operand) in case the first operand is nullish. If the first operand is not nullish, its value is returned.
Sounds complicated, but here's a simple example.
Consider a ?? b
:
- will return
a
ifa
is different thannull
andundefined
; - will return
b
ifa
is equal tonull
orundefined
.
let coffee: boolean | null | undefined;
const awaken = coffee ?? false;
awaken
will be assigned either coffee
or false
:
- if
coffee
is not nullish,awaken
will be assignedcoffee
; - if
coffee
is nullish,awaken
will be assignedfalse
.
Optional Chaining ?
Have you ever seen (or written) code like this?
if (obj && obj.prop1 && obj.prop1.prop2 && obj.prop1.prop2.prop3) {
// do something
}
Optional chaining changes how objects, properties and methods are accessed. Instead of throwing an error if they are nullish, it will short-circuit and return undefined
. Optional chaining also makes your code more readable.
This is how we could rewrite the code above with optional chaining:
if (obj?.prop1?.prop2?.prop3) {
// do something
}
Non Null Assertion !
Sometimes, TypeScript is unable to identify that some operand is nullish. The non null assertion operator !
comes in handy for those cases. You might use it when you want to tell TypeScript that at that specific point in the code, the operand is definitely not null and not undefined.
// imagine you have a state that represents an API response
interface State {
status: 'pending' | 'complete';
response: string | undefined;
};
let state: State = {
status: 'complete',
response: 'some text',
}
// we know that when status is 'complete' we must have a response
if (state.status === 'complete') {
console.log(state.response.length); // Object is possibly 'undefined'.
console.log(state.response!.length) // this works
}
Check out this post by Jennifer Wadella to learn more about the non null assertion operator in Angular.
Exponentiation **
In 2 ** 3
, raises the first operand 2
to the power of the second 3
, being equivalent to 2³.
Contrary to Math.pow(), the exponentiation operator **
works with the new BigInt values.
console.log(2 ** 3);
console.log(Math.pow(2, 3)); // the old way
Assignment Operators **=
, &&=
, ||=
, ??=
Assignment operators are shorthand for common assignment operations. For example, a += 1
is equivalent to a = a + 1
.
Assignment operators apply an operator to two arguments, then assign the result to the left operand.
Additionally, the &&=
, ||=
, ??=
operators will short-circuit, which means if the operation is evaluated to false, no assignment will occur.
a = a ** b; // a **= b, exponentiation
a = a && (a = b); // a &&= b, logical AND
a = a || (a = b); // a ||= b, logical OR
a = a ?? (a = b); // a ??= b, nullish coalescing
// a &&= b, also equivalent to:
if (a) {
a = b;
}
// a ||= b, also equivalent to:
if (!a) {
a = b;
}
// a ??= b, also equivalent to:
if (a === null || a === undefined) {
a = b;
}
These TypeScript techniques can help you handle nullish values, improve readability, manipulate larger integers, and more. I hope you find these TypeScript features useful for your Angular code!
To learn more about Angular and TypeScript, check out Bitovi Academy.