typescript-advanced-types
π―Skillfrom ovachiever/droid-tings
Enables advanced TypeScript type manipulation through generics, conditional types, mapped types, and utility types for creating robust, type-safe applications.
Part of
ovachiever/droid-tings(370 items)
Installation
git clone https://github.com/ovachiever/droid-tings.gitSkill Details
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.
Overview
# 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
Purpose: Create reusable, type-flexible components while maintaining type safety.
Basic Generic Function:
```typescript
function identity
return value;
}
const num = identity
const str = identity
const auto = identity(true); // Type inferred: boolean
```
Generic Constraints:
```typescript
interface HasLength {
length: number;
}
function logLength
console.log(item.length);
return item;
}
logLength("hello"); // OK: string has length
logLength([1, 2, 3]); // OK: array has length
logLength({ length: 10 }); // OK: object has length
// logLength(42); // Error: number has no length
```
Multiple Type Parameters:
```typescript
function merge
return { ...obj1, ...obj2 };
}
const merged = merge(
{ name: "John" },
{ age: 30 }
);
// Type: { name: string } & { age: number }
```
2. Conditional Types
Purpose: Create types that depend on conditions, enabling sophisticated type logic.
Basic Conditional Type:
```typescript
type IsString
type A = IsString
type B = IsString
```
Extracting Return Types:
```typescript
type ReturnType
function getUser() {
return { id: 1, name: "John" };
}
type User = ReturnType
// Type: { id: number; name: string; }
```
Distributive Conditional Types:
```typescript
type ToArray
type StrOrNumArray = ToArray
// Type: string[] | number[]
```
Nested Conditions:
```typescript
type TypeName
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
T extends Function ? "function" :
"object";
type T1 = TypeName
type T2 = TypeName<() => void>; // "function"
```
3. Mapped Types
Purpose: Transform existing types by iterating over their properties.
Basic Mapped Type:
```typescript
type Readonly
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly
// Type: { readonly id: number; readonly name: string; }
```
Optional Properties:
```typescript
type Partial
[P in keyof T]?: T[P];
};
type PartialUser = Partial
// Type: { id?: number; name?: string; }
```
Key Remapping:
```typescript
type Getters
[K in keyof T as get${Capitalize]: () => T[K]
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters
// Type: { getName: () => string; getAge: () => number; }
```
Filtering Properties:
```typescript
type PickByType
[K in keyof T as T[K] extends U ? K : never]: T[K]
};
interface Mixed {
id: number;
name: string;
age: number;
active: boolean;
}
type OnlyNumbers = PickByType
// Type: { id: number; age: number; }
```
4. Template Literal Types
Purpose: Create string-based types with pattern matching and transformation.
Basic Template Literal:
```typescript
type EventName = "click" | "focus" | "blur";
type EventHandler = on${Capitalize;
// Type: "onClick" | "onFocus" | "onBlur"
```
String Manipulation:
```typescript
type UppercaseGreeting = Uppercase<"hello">; // "HELLO"
type LowercaseGreeting = Lowercase<"HELLO">; // "hello"
type CapitalizedName = Capitalize<"john">; // "John"
type UncapitalizedName = Uncapitalize<"John">; // "john"
```
Path Building:
```typescript
type Path
? { [K in keyof T]: K extends string
? ${K} | ${K}.${Path
: never
}[keyof T]
: never;
interface Config {
server: {
host: string;
port: number;
};
database: {
url: string;
};
}
type ConfigPath = Path
// Type: "server" | "database" | "server.host" | "server.port" | "database.url"
```
5. Utility Types
Built-in Utility Types:
```typescript
// Partial
type PartialUser = Partial
// Required
type RequiredUser = Required
// Readonly
type ReadonlyUser = Readonly
// Pick
type UserName = Pick
// Omit
type UserWithoutPassword = Omit
// Exclude
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract
type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
// NonNullable
type T3 = NonNullable
// Record
type PageInfo = Record<"home" | "about", { title: string }>;
```
Advanced Patterns
Pattern 1: Type-Safe Event Emitter
```typescript
type EventMap = {
"user:created": { id: string; name: string };
"user:updated": { id: string };
"user:deleted": { id: string };
};
class TypedEventEmitter
private listeners: {
[K in keyof T]?: Array<(data: T[K]) => void>;
} = {};
on
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(callback);
}
emit
const callbacks = this.listeners[event];
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
const emitter = new TypedEventEmitter
emitter.on("user:created", (data) => {
console.log(data.id, data.name); // Type-safe!
});
emitter.emit("user:created", { id: "1", name: "John" });
// emitter.emit("user:created", { id: "1" }); // Error: missing 'name'
```
Pattern 2: Type-Safe API Client
```typescript
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type EndpointConfig = {
"/users": {
GET: { response: User[] };
POST: { body: { name: string; email: string }; response: User };
};
"/users/:id": {
GET: { params: { id: string }; response: User };
PUT: { params: { id: string }; body: Partial
DELETE: { params: { id: string }; response: void };
};
};
type ExtractParams
type ExtractBody
type ExtractResponse
class APIClient
async request<
Path extends keyof Config,
Method extends keyof Config[Path]
>(
path: Path,
method: Method,
...[options]: ExtractParams
? ExtractBody
? []
: [{ body: ExtractBody
: [{
params: ExtractParams
body?: ExtractBody
}]
): Promise
// Implementation here
return {} as any;
}
}
const api = new APIClient
// Type-safe API calls
const users = await api.request("/users", "GET");
// Type: User[]
const newUser = await api.request("/users", "POST", {
body: { name: "John", email: "john@example.com" }
});
// Type: User
const user = await api.request("/users/:id", "GET", {
params: { id: "123" }
});
// Type: User
```
Pattern 3: Builder Pattern with Type Safety
```typescript
type BuilderState
[K in keyof T]: T[K] | undefined;
};
type RequiredKeys
[K in keyof T]-?: {} extends Pick
}[keyof T];
type OptionalKeys
[K in keyof T]-?: {} extends Pick
}[keyof T];
type IsComplete
RequiredKeys
? S[RequiredKeys
? false
: true
: false;
class Builder
private state: S = {} as S;
set
key: K,
value: T[K]
): Builder
this.state[key] = value;
return this as any;
}
build(
this: IsComplete
): T {
return this.state as T;
}
}
interface User {
id: string;
name: string;
email: string;
age?: number;
}
const builder = new Builder
const user = builder
.set("id", "1")
.set("name", "John")
.set("email", "john@example.com")
.build(); // OK: all required fields set
// const incomplete = builder
// .set("id", "1")
// .build(); // Error: missing required fields
```
Pattern 4: Deep Readonly/Partial
```typescript
type DeepReadonly
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly
: T[P];
};
type DeepPartial
[P in keyof T]?: T[P] extends object
? T[P] extends Array
? Array
: DeepPartial
: T[P];
};
interface Config {
server: {
host: string;
port: number;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
pool: {
min: number;
max: number;
};
};
}
type ReadonlyConfig = DeepReadonly
// All nested properties are readonly
type PartialConfig = DeepPartial
// All nested properties are optional
```
Pattern 5: Type-Safe Form Validation
```typescript
type ValidationRule
validate: (value: T) => boolean;
message: string;
};
type FieldValidation
[K in keyof T]?: ValidationRule
};
type ValidationErrors
[K in keyof T]?: string[];
};
class FormValidator
constructor(private rules: FieldValidation
validate(data: T): ValidationErrors
const errors: ValidationErrors
let hasErrors = false;
for (const key in this.rules) {
const fieldRules = this.rules[key];
const value = data[key];
if (fieldRules) {
const fieldErrors: string[] = [];
for (const rule of fieldRules) {
if (!rule.validate(value)) {
fieldErrors.push(rule.message);
}
}
if (fieldErrors.length > 0) {
errors[key] = fieldErrors;
hasErrors = true;
}
}
}
return hasErrors ? errors : null;
}
}
interface LoginForm {
email: string;
password: string;
}
const validator = new FormValidator
email: [
{
validate: (v) => v.includes("@"),
message: "Email must contain @"
},
{
validate: (v) => v.length > 0,
message: "Email is required"
}
],
password: [
{
validate: (v) => v.length >= 8,
message: "Password must be at least 8 characters"
}
]
});
const errors = validator.validate({
email: "invalid",
password: "short"
});
// Type: { email?: string[]; password?: string[]; } | null
```
Pattern 6: Discriminated Unions
```typescript
type Success
status: "success";
data: T;
};
type Error = {
status: "error";
error: string;
};
type Loading = {
status: "loading";
};
type AsyncState
function handleState
switch (state.status) {
case "success":
console.log(state.data); // Type: T
break;
case "error":
console.log(state.error); // Type: string
break;
case "loading":
console.log("Loading...");
break;
}
}
// Type-safe state machine
type State =
| { type: "idle" }
| { type: "fetching"; requestId: string }
| { type: "success"; data: any }
| { type: "error"; error: Error };
type Event =
| { type: "FETCH"; requestId: string }
| { type: "SUCCESS"; data: any }
| { type: "ERROR"; error: Error }
| { type: "RESET" };
function reducer(state: State, event: Event): State {
switch (state.type) {
case "idle":
return event.type === "FETCH"
? { type: "fetching", requestId: event.requestId }
: state;
case "fetching":
if (event.type === "SUCCESS") {
return { type: "success", data: event.data };
}
if (event.type === "ERROR") {
return { type: "error", error: event.error };
}
return state;
case "success":
case "error":
return event.type === "RESET" ? { type: "idle" } : state;
}
}
```
Type Inference Techniques
1. Infer Keyword
```typescript
// Extract array element type
type ElementType
type NumArray = number[];
type Num = ElementType
// Extract promise type
type PromiseType
type AsyncNum = PromiseType
// Extract function parameters
type Parameters
function foo(a: string, b: number) {}
type FooParams = Parameters
```
2. Type Guards
```typescript
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isArrayOf
value: unknown,
guard: (item: unknown) => item is T
): value is T[] {
return Array.isArray(value) && value.every(guard);
}
const data: unknown = ["a", "b", "c"];
if (isArrayOf(data, isString)) {
data.forEach(s => s.toUpperCase()); // Type: string[]
}
```
3. Assertion Functions
```typescript
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("Not a string");
}
}
function processValue(value: unknown) {
assertIsString(value);
// value is now typed as string
console.log(value.toUpperCase());
}
```
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
Type Testing
```typescript
// Type assertion tests
type AssertEqual
[T] extends [U]
? [U] extends [T]
? true
: false
: false;
type Test1 = AssertEqual
type Test2 = AssertEqual
type Test3 = AssertEqual
// Expect error helper
type ExpectError
// Example usage
type ShouldError = ExpectError
```
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
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
Resources
- TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/
- Type Challenges: https://github.com/type-challenges/type-challenges
- TypeScript Deep Dive: https://basarat.gitbook.io/typescript/
- Effective TypeScript: Book by Dan Vanderkam
More from this repository10
nextjs-shadcn-builder skill from ovachiever/droid-tings
security-auditor skill from ovachiever/droid-tings
threejs-graphics-optimizer skill from ovachiever/droid-tings
api-documenter skill from ovachiever/droid-tings
secret-scanner skill from ovachiever/droid-tings
readme-updater skill from ovachiever/droid-tings
applying-brand-guidelines skill from ovachiever/droid-tings
Configures Tailwind v4 with shadcn/ui, automating CSS variable setup, dark mode, and preventing common initialization errors.
deep-reading-analyst skill from ovachiever/droid-tings
dependency-auditor skill from ovachiever/droid-tings