Typescript Tricks
Private Property Async Initialization
For the use cases where you run some async operation inside your class constructor and a private property in your class gets defined asynchronously, TypeScript throws an error, saying all class properties must be synchronously defined inside the constructor.
To override this behavior and tell TypeScript that you know you will assign that private property a value, you can use the !:
definite assignment assertion operator.
class MyClass {
// say this will definitely be assigned a value
private myProp!: string;
constructor() {
this.init();
}
// set private property asynchronously
async init() {
this.myProp = await someAsyncOperation();
}
}
Extract type of array entry
The (typeof arrayName)[number]
helps get the typeof an array entry.
const statuses = ["active", "inactive"] as const;
type Status = (typeof statuses)[number]; // "active" | "inactive"
Advanced Assertions
Double assertion
You can cast a variable to any type you want by using a double assertion, where you first cast the variable type as unknown
, which then allows you to cast to whatever type you desire:
const myVar = "hello" as unknown as number;
Const assertion
You can tell TypeScript that a variable is a constant by using the as const
assertion. This makes all properties of the variable and the variable itself immutable by adding a readonly
modifier to all properties and the variable itself.
Whenever you use a const assertion, you are telling typescript to infer the type as literally and as narrowly as possible.
const routes = {
home: "/",
about: "/about",
} as const;
typeof Route = (typeof routes)[keyof typeof routes]; // "/about" | "/"
const assertions are also useful when you need to type cast a string down to a string literal type:
const myVar = "hello" as const;
// myVar is now of type "hello" instead of string
You can use the as const
assertion with arrays and generics as well:
// tell typescript to type the array literally
function useStatuses<const T extends string>(statuses: T[]): T[] {
return statuses;
}
const statuses = useStatuses(["active", "inactive"]);
Complete guide to infer
You can add constraints to infer
uses, making it even more usefel.
type GetReturnTypeString<T> = T extends ((
...args: any[]
) => infer R extends string | number | boolean)
? `return type is ${R}`
: never;