10 Advanced TypeScript Tips for Writing Clean, Robust Code

TypeScript makes modern web development better with its type safety and developer tools. Ready to level up your TypeScript skills? Here are ten practical tips that’ll help you write code that’s cleaner and easier to maintain.

Whether you’re new to TypeScript or have been using it for a while, these tips will strengthen your code and catch bugs early.

Table of Contents

1. Master Type Inference

TypeScript can figure out types on its own, but knowing when to let it work its magic and when to be explicit makes a big difference in your code’s readability.

// Too vague: Relying just on inference
const user = {
  name: "John",
  age: 30
};

// Better: Clear interface with smart inference
interface User {
  name: string;
  age: number;
}

const user: User = {
  name: "John",
  age: 30
};
Code language: PHP (php)

2. Use Built-in Utility Types

TypeScript comes with handy utility types that save you time and keep your code DRY (Don’t Repeat Yourself).

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
}

// Make all properties read-only
type ReadOnlyProduct = Readonly<Product>;

// Pick just the fields you need
type ProductPreview = Pick<Product, 'name' | 'price'>;

// Make all fields optional
type PartialProduct = Partial<Product>;
Code language: PHP (php)

3. Turn On Strict Null Checks

Catch null and undefined errors early by enabling strictNullChecks in your TypeScript settings.

// tsconfig.json
{
  "compilerOptions": {
    "strictNullChecks": true
  }
}

// This will show an error
function getUserName(user: { name?: string }) {
  return user.name.toUpperCase(); // Error: name might be undefined
}

// Fixed version
function getUserName(user: { name?: string }) {
  return user.name?.toUpperCase() ?? 'ANONYMOUS';
}
Code language: JavaScript (javascript)

4. Work with Discriminated Unions

Handle different but related data types clearly and safely with discriminated unions.

type Success = {
  status: 'success';
  data: string;
};

type Error = {
  status: 'error';
  message: string;
};

type Result = Success | Error;

function handleResult(result: Result) {
  if (result.status === 'success') {
    console.log(result.data); // TypeScript knows this is a string
  } else {
    console.log(result.message); // TypeScript knows this is a string
  }
}
Code language: JavaScript (javascript)

5. Add Generic Constraints

Make your code flexible but type-safe with generic constraints.

interface HasId {
  id: number;
}

function findById<T extends HasId>(items: T[], id: number): T | undefined {
  return items.find(item => item.id === id);
}

interface User extends HasId {
  name: string;
}

const users: User[] = [
  { id: 1, name: "John" },
  { id: 2, name: "Jane" }
];

const user = findById(users, 1); // Type: User | undefined
Code language: PHP (php)

6. Create Type Guards

Type guards help you narrow down types safely and make your code more predictable.

interface Car {
  type: 'car';
  model: string;
  year: number;
}

interface Bicycle {
  type: 'bicycle';
  brand: string;
  gears: number;
}

type Vehicle = Car | Bicycle;

function isCar(vehicle: Vehicle): vehicle is Car {
  return vehicle.type === 'car';
}

function handleVehicle(vehicle: Vehicle) {
  if (isCar(vehicle)) {
    console.log(vehicle.model); // TypeScript knows it's a Car
  } else {
    console.log(vehicle.brand); // TypeScript knows it's a Bicycle
  }
}
Code language: PHP (php)

7. Create Mapped Types

Build new types from existing ones with mapped types.

type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

interface User {
  name: string;
  age: number;
}

type NullableUser = Nullable<User>;
// Creates:
// {
//   name: string | null;
//   age: number | null;
// }
Code language: PHP (php)

8. Add Const Assertions

Make your types more specific with const assertions.

const config = {
  endpoint: "api.example.com",
  method: "POST" as const,
  version: 1
} as const;

// Now config.method is exactly "POST", not just any string
// And you can't change any values in config
Code language: JavaScript (javascript)

9. Handle Dynamic Keys

Use index signatures when working with objects that have keys you don’t know ahead of time.

interface StringMap {
  [key: string]: string;
}

const headers: StringMap = {
  "Content-Type": "application/json",
  "Authorization": "Bearer token"
};
Code language: PHP (php)

10. Use Template Literal Types

Create specific string types with template literals.

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Path = `/api/${string}`;

interface ApiRequest {
  method: HttpMethod;
  path: Path;
}

// This works
const request: ApiRequest = {
  method: 'GET',
  path: '/api/users'
};

// This fails
const badRequest: ApiRequest = {
  method: 'GET',
  path: '/users' // Error: Must start with '/api/'
};
Code language: JavaScript (javascript)

Wrapping Up

These TypeScript tips will help you write safer, cleaner code that’s easier to maintain. TypeScript isn’t just about adding types to JavaScript – it’s about catching bugs early and making your development work smoother.

What TypeScript features do you find most helpful in your projects? Try these tips in your next project and see how they improve your code.

Happy coding!

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Share via
Copy link
Powered by Social Snap