🗂️ Typescript Cheat Sheet
A collection of useful typescript utilities
Function Overload
In Next.js
you can call server functions from the client side directly, however, the type hints may mislead you and cause error.
For example:
type FormData = {
name: string
age: string
}
export function serverAction(data: FormData) {
const { name, age } = data
}
We cannot trust what the client submits, the name or age prop may not exist in the real world, we should validate the data first, so change that to:
function validate(data: unknown): FormData {
// validates data here
...
return data as FormData
}
export function serverAction(data: FormData) {
const validData = validate(data)
const { name, age } = data // woops, should be validData here
}
Declaring data as FormData
type may not be a good idea, since there is no error hints when you accidentally use data.name
or data.age
, so you should change its type to unknown
export function serverAction(data: unknown) {
const validData = validate(data)
// const { name, age } = data, this will show ts error
const { name, age } = validData
}
But in this case, we lose type hints on the client side, a better solution is to add another function declaration for the client side using overload.
The final version:
type FormData = {
name: string
age: string
}
export function serverAction(data: FormData): void
export function serverAction(data: unknown) {
const validData = validate(data)
const { name, age } = validData
}
function validate(data: unknown): FormData {
// validates data here
...
return data as FormData
}
DistributiveOmit
type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
Why not just use Omit
?
interface A {
id: string
label: string
a: string
}
interface B {
id: string
label: string
b: string
}
type C = A | B
type D = Omit<C, 'id'> // can not get correct type, same as Omit<A, 'id'>
ArrayElement
type ArrayElement<T> = T extends readonly (infer E)[] ? E : never
Or simplified version
const chars = ['a', 'b', 'c']
const char: (typeof chars)[number] = 's'
Extend Third-party Module Interface
import 'module-name'
declare module 'module-name' {
export interface ToBeExtended {
prop: unknown
}
}