Unlocking TypeScript 5 Hidden Gems You May Not Know
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 | let x: number | undefined; |
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 | let scores: number[] | undefined; |
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 | type MappedTypeWithNewProperties<T> = { |
One of the common use cases of key remapping is to create a new type with renamed keys.
1 | type Person = { |
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 | let john: [string, number] = ["John", 20]; |
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 | type Person= [name: string, age: number]; |
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 | interface MyObj { |
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 | class MyStaticClass { |
The static index signature is only available for TypeScript 4.3 and above.
Use satisfies
operator to validate against another type
satisfies
is 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 | const config = { |
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 | const config2 = { |
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.