Skip to main content

TypeScript Best Practices

Learn how to write clean, maintainable TypeScript code with advanced type features and patterns.

10 min read
156 views28 likes4 comments
TypeScript Best Practices

TypeScript Best Practices

Learn how to write clean, maintainable TypeScript code that scales.

Strict Mode

Always enable strict mode in your tsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true
  }
}

Use Interfaces for Object Shapes

// βœ… Good: interface for object shapes
interface User {
  id: string
  name: string
  email: string
  createdAt: Date
}

// βœ… Good: type for unions and intersections
type Status = 'active' | 'inactive' | 'suspended'
type ApiResponse<T> = { data: T; error: null } | { data: null; error: string }

Avoid any β€” Use unknown Instead

// ❌ Bad
function parseJSON(json: string): any {
  return JSON.parse(json)
}

// βœ… Good
function parseJSON(json: string): unknown {
  return JSON.parse(json)
}

// With type guard
function isUser(data: unknown): data is User {
  return typeof data === 'object' && data !== null && 'id' in data && 'name' in data
}

Discriminated Unions

type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }
  | { kind: 'triangle'; base: number; height: number }

function area(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2
    case 'rectangle':
      return shape.width * shape.height
    case 'triangle':
      return (shape.base * shape.height) / 2
  }
}

Generic Constraints

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

// Type-safe object access
const user: User = { id: '1', name: 'Ahmed', email: '[email protected]', createdAt: new Date() }
const name = getProperty(user, 'name') // string

Utility Types

// Partial makes all properties optional
type UpdateUser = Partial<User>

// Pick selects specific properties
type UserPreview = Pick<User, 'id' | 'name'>

// Omit excludes specific properties
type CreateUser = Omit<User, 'id' | 'createdAt'>

// Record creates an object type
type UserRoles = Record<string, 'admin' | 'user' | 'viewer'>

Conclusion

Following TypeScript best practices leads to fewer bugs, better developer experience, and more maintainable codebases. Enable strict mode, prefer interfaces, avoid any, and leverage the type system to catch errors at compile time.

Share this article

Subscribe to our newsletter

Get the latest articles, tutorials, and insights delivered straight to your inbox. No spam, unsubscribe anytime.

Related Articles

Modern CSS Techniques for 2024

Modern CSS Techniques for 2024

Explore the latest CSS features including container queries, cascade layers, and advanced grid layouts.

Read more
Getting Started with Next.js 15

Getting Started with Next.js 15

Learn about the latest features in Next.js 15 including async components, improved performance, and new routing capabilities.

Read more
Authentication Best Practices

Authentication Best Practices

Implement secure authentication with JWT, OAuth, and modern security patterns for web applications.

Read more

Comments (0)