| name | typescript-expert |
| description | Advanced TypeScript: generics, conditional types, mapped types, type guards, utility types, and strict type safety patterns. |
| metadata | {"thinkfleetbot":{"emoji":"🔷","requires":{"anyBins":["npx","node"]}}} |
TypeScript Expert
Advanced type-level programming for robust, self-documenting code.
Generics
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
type ApiResponse<T = unknown> = { data: T; status: number; error?: string };
class Repository<T extends { id: string }> {
private items = new Map<string, T>();
save(item: T) { this.items.set(item.id, item); }
find(id: string): T | undefined { return this.items.get(id); }
}
Conditional Types
type ApiResult<T> = T extends 'user' ? User : T extends 'post' ? Post : never;
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type Result = UnwrapPromise<Promise<string>>;
type NonNullable<T> = T extends null | undefined ? never : T;
Mapped Types
type Partial<T> = { [K in keyof T]?: T[K] };
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
Type Guards
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'email' in value;
}
type Result<T> = { ok: true; data: T } | { ok: false; error: string };
function handle<T>(result: Result<T>) {
if (result.ok) {
console.log(result.data);
} else {
console.log(result.error);
}
}
function assertDefined<T>(value: T | undefined, msg: string): asserts value is T {
if (value === undefined) throw new Error(msg);
}
Utility Types
type UserPreview = Pick<User, 'id' | 'name'>;
type CreateUserInput = Omit<User, 'id' | 'createdAt'>;
type StrictConfig = Required<Config>;
type UserMap = Record<string, User>;
type StringOrNumber = Extract<string | number | boolean, string | number>;
type FnParams = Parameters<typeof myFunction>;
type FnReturn = ReturnType<typeof myFunction>;
Template Literal Types
type EventName = `on${Capitalize<'click' | 'hover' | 'focus'>}`;
type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = `/${string}`;
type Route = `${HTTPMethod} ${Endpoint}`;
Strict Patterns
function assertNever(x: never): never {
throw new Error(`Unexpected value: ${x}`);
}
type Status = 'active' | 'inactive' | 'pending';
function handleStatus(status: Status) {
switch (status) {
case 'active': return 'green';
case 'inactive': return 'red';
case 'pending': return 'yellow';
default: return assertNever(status);
}
}
type UserId = string & { __brand: 'UserId' };
type PostId = string & { __brand: 'PostId' };
function getUser(id: ) { }
tsconfig Strict Settings
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitOverride": true
}
}
Notes
unknown over any — forces type checking before use.
- Prefer discriminated unions over optional properties for state modeling.
as const makes literal types: const x = [1, 2] as const → readonly [1, 2].
- Avoid type assertions (
as). If you need one, you probably need a type guard instead.
- Use
satisfies to validate without widening: const config = {...} satisfies Config.