Back to the blog

TypeScript Best Practices 2024: Writing Clean Code

Modern TypeScript practices: strict typing, utility types, patterns and anti-patterns.

January 5, 2026
8 min read
597 views
MOLOTILO

MOLOTILO DIGITAL

TypeScript Best Practices 2024: Writing Clean Code

Strict Typing — is the foundation of quality

Enable all strict options в tsconfig.json for maximum type safety:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true
  }
}

Utility Types for Clean Code

TypeScript provides powerful utility types. Here are some examples:

// Partial - makes all properties optional
interface User {
  id: number;
  name: string;
  email: string;
}

type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; }

// Pick - picks only specified properties
type UserPreview = Pick<User, 'id' | 'name'>;
// { id: number; name: string; }

// Omit - omits specified properties
type UserWithoutEmail = Omit<User, 'email'>;
// { id: number; name: string; }

Generics for Reusable Code

Create universal functions using generics:

// Universal function for API requests
async function fetchData<T>(url: string): Promise<T> {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  return response.json() as Promise<T>;
}

// Usage
interface Post {
  id: number;
  title: string;
  body: string;
}

const posts = await fetchData<Post[]>('/api/posts');
const singlePost = await fetchData<Post>('/api/posts/1');

Type Guards for Safe Type Handling

Type guards help narrow variable types:

interface Dog {
  type: 'dog';
  bark(): void;
}

interface Cat {
  type: 'cat';
  meow(): void;
}

type Animal = Dog | Cat;

// Type guard function
function isDog(animal: Animal): animal is Dog {
  return animal.type === 'dog';
}

function makeSound(animal: Animal) {
  if (isDog(animal)) {
    animal.bark(); // TypeScript knows this is Dog
  } else {
    animal.meow(); // TypeScript знает, что это Cat
  }
}

Working with React Components

Proper typing of React components:

import { FC, ReactNode, useState } from 'react';

// Props with children
interface CardProps {
  title: string;
  children: ReactNode;
  onClick?: () => void;
}

const Card: FC<CardProps> = ({ title, children, onClick }) => {
  return (
    <div className="card" onClick={onClick}>
      <h2>{title}</h2>
      {children}
    </div>
  );
};

// Hooks with types
interface User {
  id: number;
  name: string;
}

function useUser() {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
  
  return { user, setUser, loading };
}

Conclusion

Following these practices, you will write more reliable and maintainable code. TypeScript — is an investment in your project quality.

Remember: strict typing during development prevents errors in production.

Enjoyed the article?

Subscribe to our blog so you don’t miss new posts