| name | typescript |
| description | TypeScript development with advanced type safety, generics, utility types, and best practices |
| category | languages |
| triggers | ["typescript","ts","type","interface","generic","type safety"] |
TypeScript
Enterprise-grade TypeScript development following industry best practices. This skill covers type system mastery, advanced patterns, generic programming, utility types, and type-safe design patterns used by top engineering teams.
Purpose
Write type-safe code that scales with confidence:
- Master TypeScript's type system
- Leverage generics for reusable code
- Use utility types effectively
- Implement type-safe patterns
- Handle complex type scenarios
- Improve code maintainability
Features
1. Type Fundamentals
const name: string = 'John';
const age: number = 30;
const isActive: boolean = true;
const numbers: number[] = [1, 2, 3];
const tuple: [string, number, boolean] = ['John', 30, true];
const namedTuple: [name: string, age: number] = ['John', 30];
interface User {
id: string;
name: string;
email: string;
age?: number;
readonly createdAt: Date;
}
type ID = string | number;
type Status = 'pending' | 'active' | 'inactive';
type Callback = (error: Error | null, result?: unknown) => void;
type StringOrNumber = string | number;
type AdminUser = User & { role: 'admin'; permissions: string[] };
type Direction = 'north' | 'south' | 'east' | 'west';
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type EventName = `on${Capitalize<string>}`;
type APIRoute = `/api/${string}`;
2. Advanced Type Patterns
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function processResult<T>(result: Result<T>): T | null {
if (result.success) {
return result.data;
} else {
console.error(result.error);
return null;
}
}
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'email' in value
);
}
function assertDefined<T>(value: T | null | undefined): asserts value is T {
(value === || value === ) {
();
}
}
<T> = T | ? : T;
<T> = T (infer U)[] ? U : ;
<T> = T (...: []) => infer R ? R : ;
<T> = { [K keyof T]: T[K] | };
<T> = { [K keyof T]?: T[K] };
<T> = { [K keyof T]: T[K] };
3. Generics
function identity<T>(value: T): T {
return value;
}
function first<T>(array: T[]): T | undefined {
return array[0];
}
function map<T, U>(array: T[], fn: (item: T) => U): U[] {
return array.map(fn);
}
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(value: T): T {
console.log(value.length);
return value;
}
interface Repository<T, ID = string> {
findById(id: ID): Promise<T | null>;
findAll(): Promise<T[]>;
create(data: Omit<T, 'id'>): Promise<T>;
update(id: ID, data: Partial<T>): Promise<T | >;
(: ): <>;
}
<T> {
: T[] = [];
(: T): {
..(item);
}
(): T | {
..();
}
(): T | {
.[.. - ];
}
}
getProperty<T, K keyof T>(: T, : K): T[K] {
obj[key];
}
4. Utility Types
interface User {
id: string;
name: string;
email: string;
password: string;
role: 'user' | 'admin';
createdAt: Date;
}
type UserUpdate = Partial<User>;
type CompleteUser = Required<User>;
type ImmutableUser = Readonly<User>;
type UserCredentials = Pick<User, 'email' | 'password'>;
type PublicUser = Omit<User, 'password'>;
type UserRoles = Record<string, User['role']>;
= <[], >;
= < >;
= < <>>;
<T> = {
[K keyof T]?: T[K] ? <T[K]> : T[K];
};
<T> = {
[K keyof T]: T[K] ? <T[K]> : T[K];
};
5. Type-Safe API Design
interface APIEndpoints {
'/users': {
GET: { response: User[]; params: { page?: number } };
POST: { response: User; body: Omit<User, 'id'> };
};
'/users/:id': {
GET: { response: User; params: { id: string } };
DELETE: { response: void; params: { id: string } };
};
}
async function apiRequest<
Path extends keyof APIEndpoints,
Method extends keyof APIEndpoints[Path]
>(
path: Path,
method: Method,
config?: APIEndpoints[Path][Method]
): Promise<APIEndpoints[Path][Method]['response']> {
const response = (path, { : method });
response.();
}
6. Error Handling Patterns
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
function ok<T>(value: T): Result<T, never> {
return { ok: true, value };
}
function err<E>(error: E): Result<never, E> {
return { ok: false, error };
}
class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500
) {
super(message);
this.name = 'AppError';
}
}
class NotFoundError extends AppError {
constructor(resource: , : ) {
(, , );
}
}
tryCatch<T>(: <T>): <<T, >> {
{
value = ();
(value);
} (error) {
(error ? error : ((error)));
}
}
7. Declaration Files
declare global {
namespace Express {
interface Request {
user?: User;
requestId: string;
}
}
}
declare global {
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test';
DATABASE_URL: string;
API_KEY: string;
}
}
}
declare module '*.svg' {
const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
export default content;
}
Use Cases
Type-Safe Redux State
interface AppState {
users: UsersState;
products: ProductsState;
}
type Action =
| { type: 'USERS_LOADED'; payload: User[] }
| { type: 'USER_ADDED'; payload: User };
function reducer(state: AppState, action: Action): AppState {
switch (action.type) {
case 'USERS_LOADED':
return { ...state, users: { items: action.payload } };
default:
return state;
}
}
Type-Safe Event Emitter
type EventMap = {
userCreated: { user: User };
userDeleted: { userId: string };
};
class TypedEventEmitter<Events extends Record<string, unknown>> {
private listeners = new Map<keyof Events, Set<(data: any) => void>>();
on<E extends keyof Events>(event: E, listener: (data: Events[E]) => void): void {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event)!.add(listener);
}
emit<E extends keyof Events>(event: E, data: Events[E]): {
..(event)?.( (data));
}
}
Best Practices
Do's
- Enable strict mode in tsconfig
- Use interfaces for object shapes
- Leverage type inference
- Use discriminated unions for state
- Prefer readonly for immutable data
- Use unknown over any
- Create reusable generic types
Don'ts
- Don't use any unless necessary
- Don't ignore errors with @ts-ignore
- Don't overuse type assertions
- Don't create overly complex generics
- Don't forget null/undefined handling
- Don't skip strict null checks
Configuration
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
References