| name | typescript-api-types |
| description | Apply when defining API request/response types, DTOs, and shared types between frontend and backend. |
| version | 1.1.0 |
| tokens | ~650 |
| confidence | high |
| sources | ["https://www.typescriptlang.org/docs/handbook/utility-types.html","https://zod.dev/"] |
| last_validated | "2025-12-10T00:00:00.000Z" |
| next_review | "2025-12-24T00:00:00.000Z" |
| tags | ["typescript","api","types","validation"] |
When to Use
Apply when defining API request/response types, DTOs, and shared types between frontend and backend.
Patterns
Pattern 1: Request/Response Types
interface User {
id: string;
email: string;
name: string;
createdAt: Date;
updatedAt: Date;
}
type CreateUserDto = Omit<User, 'id' | 'createdAt' | 'updatedAt'>;
type UpdateUserDto = Partial<Omit<User, 'id'>> & Pick<User, 'id'>;
type UserResponse = Omit<User, 'createdAt' | 'updatedAt'> & {
createdAt: string;
updatedAt: string;
};
Pattern 2: API Response Wrapper
interface ApiResponse<T> {
data: T;
meta?: {
page?: number;
limit?: number;
total?: number;
};
}
interface ApiError {
error: {
code: string;
message: string;
details?: Record<string, string[]>;
};
}
type ApiResult<T> = ApiResponse<T> | ApiError;
function isApiError(result: ApiResult<unknown>): result is ApiError {
return 'error' in result;
}
Pattern 3: Zod Schema as Single Source
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1),
role: z.enum(['user', 'admin']),
});
type User = z.infer<typeof UserSchema>;
const CreateUserSchema = UserSchema.omit({ id: true });
type CreateUserDto = z.infer<typeof CreateUserSchema>;
const UpdateUserSchema = UserSchema.partial().required({ id: true });
type UpdateUserDto = z.infer<typeof UpdateUserSchema>;
Pattern 4: Shared Types Package
export interface User { }
export type CreateUserDto = Omit<User, 'id'>;
Pattern 5: API Endpoint Type Map
interface ApiEndpoints {
'GET /users': { response: User[] };
'GET /users/:id': { params: { id: string }; response: User };
'POST /users': { body: CreateUserDto; response: User };
'PUT /users/:id': { params: { id: string }; body: UpdateUserDto; response: User };
'DELETE /users/:id': { params: { id: string }; response: void };
}
async function api<K extends keyof ApiEndpoints>(
endpoint: K,
options?: Omit<ApiEndpoints[K], 'response'>
): Promise<ApiEndpoints[K]['response']> {
}
Pattern 6: NoInfer for Strict Type Matching (TypeScript 5.4+)
function validateStatus<S extends string>(
validStatuses: S[],
currentStatus: NoInfer<S>
): boolean {
return validStatuses.includes(currentStatus);
}
validateStatus(['pending', 'active', 'done'], 'active');
validateStatus(['pending', 'active', 'done'], 'invalid');
Anti-Patterns
- Duplicate types - Single source of truth (Zod or interface)
- Manual JSON date parsing - Use consistent date handling
any for API responses - Type everything
- Frontend/backend type drift - Use shared types package
Verification Checklist