TypeScript
TypeScript Best Practices
Discover the latest TypeScript patterns and practices that will help you write more maintainable and type-safe code.
Use Strict Mode
Always enable strict mode in your tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}
This catches many common errors at compile time rather than runtime.
Prefer Type Inference
Let TypeScript infer types when possible:
// Good
const user = { name: "John", age: 30 }
// Unnecessary
const user: { name: string; age: number } = { name: "John", age: 30 }
Use Union Types Over Enums
Union types are more flexible and tree-shakeable:
// Prefer this
type Status = "pending" | "approved" | "rejected"
// Over this
enum Status {
Pending = "pending",
Approved = "approved",
Rejected = "rejected"
}
Leverage Type Guards
Type guards help TypeScript narrow types:
function isString(value: unknown): value is string {
return typeof value === "string"
}
function processValue(value: string | number) {
if (isString(value)) {
// TypeScript knows value is string here
console.log(value.toUpperCase())
}
}
Use unknown Instead of any
The unknown type is safer than any:
// Avoid
function process(data: any) {
return data.value // No type checking
}
// Better
function process(data: unknown) {
if (typeof data === "object" && data !== null && "value" in data) {
return data.value
}
}
Utility Types Are Your Friend
TypeScript provides powerful utility types:
Partial<T>: Make all properties optionalRequired<T>: Make all properties requiredPick<T, K>: Select specific propertiesOmit<T, K>: Exclude specific propertiesRecord<K, T>: Create an object type with specific keys
interface User {
id: string
name: string
email: string
age: number
}
type UserPreview = Pick<User, "id" | "name">
type UserUpdate = Partial<Omit<User, "id">>
Sam Fortin