My-opencode-config typescript-advanced-types
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects.
git clone https://github.com/flpbalada/my-opencode-config
T=$(mktemp -d) && git clone --depth=1 https://github.com/flpbalada/my-opencode-config "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/typescript-advanced-types" ~/.claude/skills/flpbalada-my-opencode-config-typescript-advanced-types && rm -rf "$T"
skills/typescript-advanced-types/SKILL.mdTypeScript Advanced Types
Comprehensive guidance for mastering TypeScript's advanced type system including generics, conditional types, mapped types, template literal types, and utility types for building robust, type-safe applications.
When to Use This Skill
- Building type-safe libraries or frameworks
- Creating reusable generic components
- Implementing complex type inference logic
- Designing type-safe API clients
- Building form validation systems
- Creating strongly-typed configuration objects
- Implementing type-safe state management
- Migrating JavaScript codebases to TypeScript
Core Concepts
1. Generics
Create reusable, type-flexible components while maintaining type safety.
function identity<T>(value: T): T { return value; } const num = identity<number>(42); // Type: number const str = identity<string>("hello"); // Type: string const auto = identity(true); // Type inferred: boolean
2. Conditional Types
Create types that depend on conditions.
type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false
3. Mapped Types
Transform existing types by iterating over their properties.
type Readonly<T> = { readonly [P in keyof T]: T[P]; }; type Partial<T> = { [P in keyof T]?: T[P]; };
4. Template Literal Types
Create string-based types with pattern matching.
type EventName = "click" | "focus" | "blur"; type EventHandler = `on${Capitalize<EventName>}`; // Type: "onClick" | "onFocus" | "onBlur"
5. Utility Types
Built-in utility types for common transformations:
Partial<T> // Make all properties optional Required<T> // Make all properties required Readonly<T> // Make all properties readonly Pick<T, K> // Select specific properties Omit<T, K> // Remove specific properties
The Golden Rule of Generics
If a type parameter appears only in the function signature, it's likely unnecessary.
// Bad - T only appears in signature, not in return or body function getRelationName<T extends 'department' | 'location'>( data: Career['data'], field: T ): string | null { return data?.[field]?.name ?? null } // Good - no unnecessary generic, use union directly function getRelationName( data: Career['data'], field: 'department' | 'location' | 'employmentType' ): string | null { return data?.[field]?.name ?? null }
Progressive Disclosure
This skill provides detailed examples through context files. Load them when needed:
| Context File | When to Load |
|---|---|
| Need generics, conditionals, mapped types examples |
| Implementing real-world patterns (EventEmitter, API client, Builder) |
| Type inference, guards, assertions, testing |
Type Inference Techniques
Infer Keyword
type ElementType<T> = T extends (infer U)[] ? U : never; type PromiseType<T> = T extends Promise<infer U> ? U : never; type Parameters<T> = T extends (...args: infer P) => any ? P : never;
Type Guards
function isString(value: unknown): value is string { return typeof value === "string"; } function isArrayOf<T>( value: unknown, guard: (item: unknown) => item is T ): value is T[] { return Array.isArray(value) && value.every(guard); }
Assertion Functions
function assertIsString(value: unknown): asserts value is string { if (typeof value !== "string") { throw new Error("Not a string"); } }
StrictOmit for Safer Property Exclusion
// Problem: Omit doesn't validate key exists type UserWithoutPassword = Omit<User, 'passwrod'>; // No error for typo // Solution: StrictOmit validates the key exists type StrictOmit<T, K extends keyof T> = Omit<T, K>; type SafeUser = StrictOmit<User, 'passwrod'>; // TypeScript error!
Branded Types for Nominal Typing
type UniformResourceLocator = string & { _brand: 'url' }; const isURL = (candidate: unknown): candidate is UniformResourceLocator => { return z.url().safeParse(candidate).success; }; function fetchFromAPI(url: UniformResourceLocator) { /* ... */ } const url = 'https://example.com'; // fetchFromAPI(url); // Error! Not branded if (isURL(url)) { fetchFromAPI(url); // OK - type guard validated }
Best Practices
- Use
overunknown
: Enforce type checkingany - Prefer
for object shapes: Better error messagesinterface - Use
for unions and complex types: More flexibletype - Leverage type inference: Let TypeScript infer when possible
- Create helper types: Build reusable type utilities
- Use const assertions: Preserve literal types
- Avoid type assertions: Use type guards instead
- Document complex types: Add JSDoc comments
- Use strict mode: Enable all strict compiler options
- Test your types: Use type tests to verify type behavior
Common Pitfalls
- Over-using
: Defeats the purpose of TypeScriptany - Ignoring strict null checks: Can lead to runtime errors
- Too complex types: Can slow down compilation
- Not using discriminated unions: Misses type narrowing opportunities
- Forgetting readonly modifiers: Allows unintended mutations
- Circular type references: Can cause compiler errors
- Not handling edge cases: Like empty arrays or null values
- Unused generic parameters: Violate the Golden Rule
Performance Considerations
- Avoid deeply nested conditional types
- Use simple types when possible
- Cache complex type computations
- Limit recursion depth in recursive types
- Use build tools to skip type checking in production
Infer Types from Zod Schemas
// Avoid duplication const userSchema = z.object({ id: z.string(), name: z.string(), email: z.string().email(), }); type User = z.infer<typeof userSchema>;