Unlocking TypeScript 5 Hidden Gems You May Not Know

Unlocking TypeScript 5 Hidden Gems You May Not Know

Sunny Sun Lv4

TypeScript is rapidly evolving, with each new release introducing features that aim to make the language more concise, powerful, and faster. While the extensive language feature is a blessing, it can also make it challenging for developers to keep up.

In this article, I will walk through five lesser-known yet incredibly useful TypeScript features and explore how to use them to enhance your TypeScript development experience.

Short-Circuiting Assignment Operators

Short-circuiting assignment operators are introduced in TypeScript 4.0. It allows you to perform multiple operations in a single line of code. Consider the following example.

1
2
3
4
5
6
7
let x: number | undefined;  
// Without short-circuiting assignment
if (!x) {
x= 42;
}
// With short-circuiting assignment
x ||= 42; // x is 42 if null

Here, the “||=” operator assigns the value 42 to “x” if it’s null or undefined. This can be a useful shorthand for writing if statements and can help reduce the amount of code you need to write.

Three operators are supported, including logical and (&&), logical or (||), and nullish coalescing (??). Below is another example:

1
2
3
4
5
6
7
8
9
let scores: number[] | undefined;  

// Without short-circuiting assignment
if(!!scores){
scores = [];
scores.push(99);
}
// With short-circuiting assignment
(scores??= []).push(99);

As shown in the example, using the new short-circuiting assignment operator make the code more concise.

Key Remapping in Mapped Types

Key remapping in mapped types is a powerful feature that allows renaming keys in an object type.

To perform key remapping, We need to use the as keyword followed by a type expression that describes the new key. Below is the basic syntax:

1
2
3
type MappedTypeWithNewProperties<T> = {  
[Properties in keyof T as NewKeyType]: Type[Properties]
}

One of the common use cases of key remapping is to create a new type with renamed keys.

1
2
3
4
5
6
7
8
9
10
11
type Person = {  
name: string;
age: number;
};
type NewPerson = {
[K in keyof Person as `new_${string & K}`]: Person[K];
};
const John : NewPerson = {
new_name: 'John',
new_age: 10
}

In the above example, the NewPerson type uses a mapped type to rename the keys in the Person type. The K variable represents the keys in the Person type, and the new_${string & K} syntax is used to rename the keys. This can be useful when you want to derive a new type based on an existing Type.

You can also use this feature to add or remove keys, making creating a well-constrained type system for your App more flexible.

Labeled Tuple Elements

In TypeScript, Tuple is a data structure that allows us to store a fixed-size sequence of elements of different types. The value of a tuple can be accessed via array-style indexing:

1
2
let john: [string, number] = ["John", 20];  
let age_of_John: number= john[1];

As shown above, using indexing is hard to express the intent. We also need to ensure the type of the element is correct. Otherwise, an error will be thrown.

Labeled tuple elements are a feature introduced in TypeScript 4.0. It allows you to label the elements of a tuple. Below is an example:

1
2
3
4
type Person= [name: string, age: number];  
const myTuple: Person = ['John', 30];
console.log(myTuple.name); // 'John'
console.log(myTuple.age); // 30

Here, the elements of the MyTuple type are labeled as name and age, makes it more readable. The labels can also be used to access the tuple’s elements, which can be especially useful when working with complex data structures.

Use Index Signatures to define an Object with an unknown structure

Index signatures in TypeScript provide a way to define an object’s properties with a dynamic key. This is useful when we know the type of the properties, but the names of the properties are unknown. To use index signatures, we need to declare the key type as below.

1
{ [key: KeyType]: ValueType }

Below is an example:

1
2
3
4
5
6
7
8
9
interface MyObj {  
[key: string]: number;
}

const obj: MyObj = {
foo: 1,
bar: 2,
baz: 3
};

Here, we defined an interface MyObj with an index signature [key: string]: number. This means that MyObj can have any number of properties with string keys and number values. We then created an object obj that conforms to the MyObj interface, with properties foo, bar, and baz.

The key of the index signature can only be a string, number, symbol or template literal type. If you try to use other types, an error will be thrown.

Error when trying to use number array to key

Note that you can also use index signatures with static properties.

1
2
3
4
5
class MyStaticClass {  
static [key: string]: number;
}

MyStaticClass.foo = 1;

The static index signature is only available for TypeScript 4.3 and above.

Use satisfies operator to validate against another type

satisfiesis a new feature that was introduced in TypeScript 4.9. It allows developers to define a type that must satisfy certain types but not affect the original type. This will be useful when you want to ensure that a type conforms to a specific set of rules and preserve the original type simultaneously.

Let’s say we have a config object containing name and count properties.

1
2
3
4
5
6
7
8
9
10
const config = {  
name: 'My App',
count: 5
}

type ConfigType = Record<'name'|'count', number | string>;
const config: ConfigType = {
name: 'My App',
count: 5
}

we can use a ConfigType to apply type constraint to it so that we can catch any typo in compile time.

But there is a side effect of this approach; we lost the original type inference. The count property was a number type, and now it has become a union of string | number.

The satisfies operator provides a better solution.

1
2
3
4
const config2 = {  
name: 'My App'
count: 10,
} satisfies ConfigType;

Here we use satisfies to validate the object with ConfigType, and simultaneously, the original type inference is preserved.

In this article, we discuss 5 TypeScript hidden gems. They can help you to write clean and type-safe code when used in the right place.

I hope you find the article useful. Happy coding!

  • Title: Unlocking TypeScript 5 Hidden Gems You May Not Know
  • Author: Sunny Sun
  • Created at : 2023-08-01 00:00:00
  • Updated at : 2024-07-07 13:49:46
  • Link: http://coffeethinkcode.com/2023/08/01/unlocking-typescript-5-hidden-gems/
  • License: This work is licensed under CC BY-NC-SA 4.0.