typescript-advanced-types
TypeScript 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 |
|---|---|
context/core-examples.md |
Need generics, conditionals, mapped types examples |
context/patterns.md |
Implementing real-world patterns (EventEmitter, API client, Builder) |
context/techniques.md |
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
unknownoverany: Enforce type checking - Prefer
interfacefor object shapes: Better error messages - Use
typefor unions and complex types: More flexible - 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
any: Defeats the purpose of TypeScript - 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>;
References
More from flpbalada/fb-skills
progressive-disclosure
Reduce complexity by revealing information progressively. Use when designing
7discuss-task
Clarify ambiguous tasks before action. Use when goal, scope, success criteria, constraints, or risks are unclear.
4cognitive-fluency-psychology
Apply cognitive fluency principles to improve clarity, trust, and conversion.
4react-useeffect-avoid
Guides when NOT to use useEffect and suggests better alternatives. Use when reviewing React code, troubleshooting performance, or considering useEffect for derived state or form resets.
4discuss-code
Critically discuss code issues with compact findings. Use when code needs review for logic, simplicity, structure, naming, or maintainability.
4learn
Extract reusable patterns from the current session. Use when errors, debugging techniques, workarounds, or project conventions should become skills.
3