TypeScript
JavaScript
Programming
Frontend
Advanced
Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan
TypeScript's type system is incredibly powerful — it's essentially a programming language in itself. Most developers only scratch the surface with basic types and interfaces. Let's dive deep into the patterns that will transform your TypeScript code.
Most developers know basic generics, but few use them to their full potential:
typescript// Basic generic
function identity<T>(arg: T): T {
return arg;
}
// Constrained generic
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Generic with default
function createState<T = string>(initial: T) {
let state = initial;
return {
get: () => state,
set: (value: T) => { state = value; }
};
}
typescriptinterface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Make all properties optional
type PartialUser = Partial<User>;
// Make all properties required
type RequiredUser = Required<User>;
// Pick specific properties
type PublicUser = Pick<User, 'id' | 'name' | 'email'>;
// Omit specific properties
type UserWithoutPassword = Omit<User, 'password'>;
// Make properties readonly
type ReadonlyUser = Readonly<User>;
// Record type for dictionaries
type UserRoles = Record<string, 'admin' | 'user' | 'moderator'>;
typescripttype IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// Practical example: extract return type
type ApiResponse<T> = T extends (...args: any[]) => Promise<infer R> ? R : never;
async function fetchUser() {
return { id: 1, name: "John" };
}
type UserData = ApiResponse<typeof fetchUser>; // { id: number; name: string }
typescripttype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = '/users' | '/posts' | '/comments';
type ApiRoute = `${HttpMethod} ${Endpoint}`;
// "GET /users" | "GET /posts" | "POST /users" | ... (12 combinations)
// Event handler pattern
type EventName = 'click' | 'focus' | 'blur';
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"
typescriptinterface Dog { bark(): void; breed: string; }
interface Cat { purr(): void; color: string; }
// Type predicate
function isDog(animal: Dog | Cat): animal is Dog {
return 'bark' in animal;
}
function handleAnimal(animal: Dog | Cat) {
if (isDog(animal)) {
animal.bark(); // TypeScript knows this is Dog
} else {
animal.purr(); // TypeScript knows this is Cat
}
}
typescripttype Result<T> =
| { status: 'success'; data: T }
| { status: 'error'; error: string }
| { status: 'loading' };
function handleResult(result: Result<User>) {
switch (result.status) {
case 'success':
console.log(result.data); // TypeScript knows data exists
break;
case 'error':
console.error(result.error); // TypeScript knows error exists
break;
case 'loading':
console.log('Loading...');
break;
}
}
Mastering these patterns will make your TypeScript code safer, more expressive, and more maintainable.