Skip to main content

TypeScript Tips & Best Practices

Generic Types

// Generic function
function identity<T>(arg: T): T {
return arg;
}

// Generic interface
interface Container<T> {
value: T;
getValue(): T;
}

// Generic class
class DataStore<T> {
private data: T[] = [];

add(item: T): void {
this.data.push(item);
}

getAll(): T[] {
return this.data;
}
}

Utility Types

// Pick - Select specific properties
interface User {
id: number;
name: string;
email: string;
age: number;
}

type UserPreview = Pick<User, 'id' | 'name'>;

// Omit - Exclude specific properties
type CreateUser = Omit<User, 'id'>;

// Partial - Make all properties optional
type UpdateUser = Partial<User>;

// Required - Make all properties required
type CompleteUser = Required<User>;

Type Guards

// Type guard function
function isString(value: unknown): value is string {
return typeof value === 'string';
}

// Using type guards
function processValue(value: string | number) {
if (isString(value)) {
// TypeScript knows value is string here
return value.toUpperCase();
} else {
// TypeScript knows value is number here
return value.toFixed(2);
}
}

Advanced Patterns

// Mapped types
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};

// Conditional types
type NonNullable<T> = T extends null | undefined ? never : T;

// Template literal types
type EventName<T extends string> = `on${Capitalize<T>}`;
type ButtonEvents = EventName<'click' | 'hover'>; // "onClick" | "onHover"