TypeScript Best Practices
TypeScript Best Practices
TypeScript has become the standard for large-scale JavaScript applications. Here are some best practices to help you write more maintainable and robust TypeScript code.
Type Definitions
Use Explicit Types
Be explicit about your types when TypeScript's inference isn't clear:
// Good
const users: User[] = getUsers();
// Avoid when type is complex
const users = getUsers();
Leverage Interfaces and Types
Use interfaces for object shapes and types for unions, intersections, and primitives:
// Object shape - use interface
interface User {
id: number;
name: string;
email: string;
}
// Union type - use type
type Status = 'pending' | 'approved' | 'rejected';
Readonly Properties
Use readonly for properties that shouldn't change:
interface Config {
readonly apiUrl: string;
readonly timeout: number;
}
Function Types
Define Return Types
Explicitly define function return types for better documentation and error catching:
function getUser(id: number): User | undefined {
// Implementation
}
Use Function Type Expressions
Define reusable function types:
type ErrorHandler = (error: Error) => void;
function registerErrorHandler(handler: ErrorHandler) {
// Implementation
}
Advanced Types
Discriminated Unions
Use discriminated unions for type-safe handling of different shapes:
type Action =
| { type: 'INCREMENT'; payload: number }
| { type: 'DECREMENT'; payload: number }
| { type: 'RESET' };
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'INCREMENT':
return state + action.payload;
case 'DECREMENT':
return state - action.payload;
case 'RESET':
return 0;
}
}
Utility Types
Leverage TypeScript's utility types:
// Make all properties optional
type PartialUser = Partial<User>;
// Make all properties required
type RequiredUser = Required<User>;
// Extract a subset of properties
type UserCredentials = Pick<User, 'email' | 'password'>;
// Omit certain properties
type PublicUser = Omit<User, 'password'>;
Project Configuration
Strict Mode
Enable strict mode in your tsconfig.json:
{
"compilerOptions": {
"strict": true
}
}
Organize Imports
Use import organization and consistent naming:
// Group imports
import React, { useState, useEffect } from 'react';
import { User, Role } from './types';
import { fetchUsers } from './api';
// Use consistent naming
import * as UserAPI from './user-api';
By following these best practices, you'll write TypeScript code that's more maintainable, less prone to bugs, and easier for other developers to understand.