Loading...
Loading...
Compare original and translation side by side
type-festtype-fest// Bad: Infinite recursion
type BadRecursive<T> = T extends object ? BadRecursive<T[keyof T]> : T;
// Good: Depth limiting with tuple counter
type GoodRecursive<T, D extends readonly number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]> =
D['length'] extends 0
? T
: T extends object
? GoodRecursive<T[keyof T], Tail<D>>
: T;
type Tail<T extends readonly unknown[]> = T extends readonly [unknown, ...infer Rest] ? Rest : [];type SafeDeepType<T> = T extends object
? T extends Function
? T
: { [K in keyof T]: SafeDeepType<T[K]> }
: T;
// When recursion limit hit, fall back to any for specific cases
type FallbackDeepType<T, D extends number = 10> = D extends 0
? T extends object ? any : T
: T extends object
? { [K in keyof T]: FallbackDeepType<T[K], [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9][D]> }
: T;// Instead of deeply recursive, use flattened approach
type FlattenObject<T> = T extends object
? T extends any[]
? T
: { [K in keyof T]: T[K] }
: T;tsc --extendedDiagnostics// Bad: Infinite recursion
type BadRecursive<T> = T extends object ? BadRecursive<T[keyof T]> : T;
// Good: Depth limiting with tuple counter
type GoodRecursive<T, D extends readonly number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]> =
D['length'] extends 0
? T
: T extends object
? GoodRecursive<T[keyof T], Tail<D>>
: T;
type Tail<T extends readonly unknown[]> = T extends readonly [unknown, ...infer Rest] ? Rest : [];type SafeDeepType<T> = T extends object
? T extends Function
? T
: { [K in keyof T]: SafeDeepType<T[K]> }
: T;
// When recursion limit hit, fall back to any for specific cases
type FallbackDeepType<T, D extends number = 10> = D extends 0
? T extends object ? any : T
: T extends object
? { [K in keyof T]: FallbackDeepType<T[K], [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9][D]> }
: T;// Instead of deeply recursive, use flattened approach
type FlattenObject<T> = T extends object
? T extends any[]
? T
: { [K in keyof T]: T[K] }
: T;tsc --extendedDiagnostics// Ensure T meets both constraints
function process<T extends BaseType>(value: T & { required: string }): T {
return value;
}// Before: Weak constraint
interface Handler<T> {
handle(item: T): void;
}
// After: Strong constraint
interface Handler<T extends { id: string; type: string }> {
handle(item: T): void;
}declare const __brand: unique symbol;
type Brand<T, TBrand> = T & { [__brand]: TBrand };
type UserId = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;
function processOrder(orderId: OrderId, userId: UserId) {
// Type-safe: cannot accidentally swap parameters
}// Ensure T meets both constraints
function process<T extends BaseType>(value: T & { required: string }): T {
return value;
}// Before: Weak constraint
interface Handler<T> {
handle(item: T): void;
}
// After: Strong constraint
interface Handler<T extends { id: string; type: string }> {
handle(item: T): void;
}declare const __brand: unique symbol;
type Brand<T, TBrand> = T & { [__brand]: TBrand };
type UserId = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;
function processOrder(orderId: OrderId, userId: UserId) {
// Type-safe: cannot accidentally swap parameters
}// Bad: T not in scope for return type
interface Container {
get<T>(): T; // T is only scoped to this method
}
// Good: T available throughout interface
interface Container<T> {
get(): T;
set(value: T): void;
}type ExtractGeneric<T> = T extends Promise<infer U>
? U
: T extends (infer V)[]
? V
: never;// Bad: T not in scope for return type
interface Container {
get<T>(): T; // T is only scoped to this method
}
// Good: T available throughout interface
interface Container<T> {
get(): T;
set(value: T): void;
}type ExtractGeneric<T> = T extends Promise<infer U>
? U
: T extends (infer V)[]
? V
: never;// Bad: Cross-type key usage
type BadPick<T, K extends keyof T, U> = {
[P in K]: U[P]; // Error: P might not exist in U
};
// Good: Constrained key mapping
type GoodPick<T, K extends keyof T> = {
[P in K]: T[P];
};type SafeGet<T, K extends PropertyKey> = K extends keyof T ? T[K] : never;
function safeGet<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}// Bad: Cross-type key usage
type BadPick<T, K extends keyof T, U> = {
[P in K]: U[P]; // Error: P might not exist in U
};
// Good: Constrained key mapping
type GoodPick<T, K extends keyof T> = {
[P in K]: T[P];
};type SafeGet<T, K extends PropertyKey> = K extends keyof T ? T[K] : never;
function safeGet<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}// Complex string manipulation
type CamelCase<S extends string> =
S extends `${infer First}_${infer Rest}`
? `${First}${Capitalize<CamelCase<Rest>>}`
: S;
type KebabToCamel<T extends string> =
T extends `${infer Start}-${infer Middle}${infer End}`
? `${Start}${Uppercase<Middle>}${KebabToCamel<End>}`
: T;// URL path parsing
type ParsePath<T extends string> =
T extends `/${infer Segment}/${infer Rest}`
? [Segment, ...ParsePath<`/${Rest}`>]
: T extends `/${infer Last}`
? [Last]
: [];
type ApiPath = ParsePath<"/api/v1/users/123">; // ["api", "v1", "users", "123"]// Complex string manipulation
type CamelCase<S extends string> =
S extends `${infer First}_${infer Rest}`
? `${First}${Capitalize<CamelCase<Rest>>}`
: S;
type KebabToCamel<T extends string> =
T extends `${infer Start}-${infer Middle}${infer End}`
? `${Start}${Uppercase<Middle>}${KebabToCamel<End>}`
: T;// URL path parsing
type ParsePath<T extends string> =
T extends `/${infer Segment}/${infer Rest}`
? [Segment, ...ParsePath<`/${Rest}`>]
: T extends `/${infer Last}`
? [Last]
: [];
type ApiPath = ParsePath<"/api/v1/users/123">; // ["api", "v1", "users", "123"]// Distributive (default behavior)
type DistributiveExample<T> = T extends string ? T : never;
type Result1 = DistributiveExample<string | number>; // string
// Non-distributive (wrapped in array)
type NonDistributive<T> = [T] extends [string] ? T : never;
type Result2 = NonDistributive<string | number>; // nevertype Distribute<T, U> = T extends U ? T : never;
type NoDistribute<T, U> = [T] extends [U] ? T : never;
// Practical example: Extract string types from union
type ExtractStrings<T> = Distribute<T, string>;
type OnlyStrings = ExtractStrings<string | number | boolean>; // string
// Extract exact union match
type ExactMatch<T, U> = NoDistribute<T, U>;
type IsExactStringOrNumber<T> = ExactMatch<T, string | number>;// Distributive (default behavior)
type DistributiveExample<T> = T extends string ? T : never;
type Result1 = DistributiveExample<string | number>; // string
// Non-distributive (wrapped in array)
type NonDistributive<T> = [T] extends [string] ? T : never;
type Result2 = NonDistributive<string | number>; // nevertype Distribute<T, U> = T extends U ? T : never;
type NoDistribute<T, U> = [T] extends [U] ? T : never;
// Practical example: Extract string types from union
type ExtractStrings<T> = Distribute<T, string>;
type OnlyStrings = ExtractStrings<string | number | boolean>; // string
// Extract exact union match
type ExactMatch<T, U> = NoDistribute<T, U>;
type IsExactStringOrNumber<T> = ExactMatch<T, string | number>;// Generic null/undefined guard
function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
// Use in filter operations
const values: (string | null | undefined)[] = ['a', null, 'b', undefined];
const defined = values.filter(isDefined); // string[]function assertIsDefined<T>(value: T | null | undefined): asserts value is T {
if (value === null || value === undefined) {
throw new Error('Value must not be null or undefined');
}
}
function processUser(user: User | null) {
assertIsDefined(user);
console.log(user.name); // TypeScript knows user is defined
}// Generic null/undefined guard
function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined;
}
// Use in filter operations
const values: (string | null | undefined)[] = ['a', null, 'b', undefined];
const defined = values.filter(isDefined); // string[]function assertIsDefined<T>(value: T | null | undefined): asserts value is T {
if (value === null || value === undefined) {
throw new Error('Value must not be null or undefined');
}
}
function processUser(user: User | null) {
assertIsDefined(user);
console.log(user.name); // TypeScript knows user is defined
}function isOfType<T>(
value: unknown,
guard: (x: unknown) => x is T
): value is T {
return guard(value);
}
function isString(x: unknown): x is string {
return typeof x === 'string';
}
function processUnknown(value: unknown) {
if (isOfType(value, isString)) {
console.log(value.length); // OK: value is string
}
}interface Schema<T> {
parse(input: unknown): T;
safeParse(input: unknown): { success: true; data: T } | { success: false; error: string };
}
function createStringSchema(): Schema<string> {
return {
parse(input: unknown): string {
if (typeof input !== 'string') {
throw new Error('Expected string');
}
return input;
},
safeParse(input: unknown) {
if (typeof input === 'string') {
return { success: true, data: input };
}
return { success: false, error: 'Expected string' };
}
};
}function isOfType<T>(
value: unknown,
guard: (x: unknown) => x is T
): value is T {
return guard(value);
}
function isString(x: unknown): x is string {
return typeof x === 'string';
}
function processUnknown(value: unknown) {
if (isOfType(value, isString)) {
console.log(value.length); // OK: value is string
}
}interface Schema<T> {
parse(input: unknown): T;
safeParse(input: unknown): { success: true; data: T } | { success: false; error: string };
}
function createStringSchema(): Schema<string> {
return {
parse(input: unknown): string {
if (typeof input !== 'string') {
throw new Error('Expected string');
}
return input;
},
safeParse(input: unknown) {
if (typeof input === 'string') {
return { success: true, data: input };
}
return { success: false, error: 'Expected string' };
}
};
}// Bad: Direct circular reference
type Node = {
value: string;
children: Node[];
};
// Good: Interface with self-reference
interface TreeNode {
value: string;
children: TreeNode[];
parent?: TreeNode;
}type Json = string | number | boolean | null | JsonObject | JsonArray;
interface JsonObject { [key: string]: Json; }
interface JsonArray extends Array<Json> {}
// Deferred evaluation for complex structures
type SafeJson<T = unknown> = T extends string | number | boolean | null
? T
: T extends object
? T extends any[]
? SafeJson<T[number]>[]
: { [K in keyof T]: SafeJson<T[K]> }
: never;// Bad: Direct circular reference
type Node = {
value: string;
children: Node[];
};
// Good: Interface with self-reference
interface TreeNode {
value: string;
children: TreeNode[];
parent?: TreeNode;
}type Json = string | number | boolean | null | JsonObject | JsonArray;
interface JsonObject { [key: string]: Json; }
interface JsonArray extends Array<Json> {}
// Deferred evaluation for complex structures
type SafeJson<T = unknown> = T extends string | number | boolean | null
? T
: T extends object
? T extends any[]
? SafeJson<T[number]>[]
: { [K in keyof T]: SafeJson<T[K]> }
: never;// Bad: Type alias self-reference
type LinkedList<T> = {
value: T;
next: LinkedList<T> | null; // Error
};
// Good: Interface approach
interface LinkedList<T> {
value: T;
next: LinkedList<T> | null;
}interface NodeA {
type: 'A';
child?: NodeB;
}
interface NodeB {
type: 'B';
children: NodeA[];
}
type TreeNode = NodeA | NodeB;// Bad: Type alias self-reference
type LinkedList<T> = {
value: T;
next: LinkedList<T> | null; // Error
};
// Good: Interface approach
interface LinkedList<T> {
value: T;
next: LinkedList<T> | null;
}interface NodeA {
type: 'A';
child?: NodeB;
}
interface NodeB {
type: 'B';
children: NodeA[];
}
type TreeNode = NodeA | NodeB;undefinedundefined
**Solutions**:
1. **Optimize type complexity**:
```typescript
// Bad: Complex union with many members
type BadStatus = 'loading' | 'success' | 'error' | 'pending' | 'cancelled' |
'retrying' | 'failed' | 'completed' | 'paused' | 'resumed' | /* ... 50+ more */;
// Good: Grouped discriminated unions
type RequestStatus =
| { phase: 'initial'; status: 'loading' | 'pending' }
| { phase: 'processing'; status: 'running' | 'paused' | 'retrying' }
| { phase: 'complete'; status: 'success' | 'error' | 'cancelled' };{
"compilerOptions": {
"incremental": true,
"skipLibCheck": true,
"composite": true
}
}
**解决方案**:
1. **优化类型复杂度**:
```typescript
// Bad: Complex union with many members
type BadStatus = 'loading' | 'success' | 'error' | 'pending' | 'cancelled' |
'retrying' | 'failed' | 'completed' | 'paused' | 'resumed' | /* ... 50+ more */;
// Good: Grouped discriminated unions
type RequestStatus =
| { phase: 'initial'; status: 'loading' | 'pending' }
| { phase: 'processing'; status: 'running' | 'paused' | 'retrying' }
| { phase: 'complete'; status: 'success' | 'error' | 'cancelled' };{
"compilerOptions": {
"incremental": true,
"skipLibCheck": true,
"composite": true
}
}// Bad: Massive single interface
interface MegaInterface {
// ... 1000+ properties
}
// Good: Composed from smaller interfaces
interface CoreData { /* essential props */ }
interface MetaData { /* metadata props */ }
interface ApiData { /* API-related props */ }
type CompleteData = CoreData & MetaData & ApiData;// Cache complex types
type ComplexUtility<T> = T extends object
? { [K in keyof T]: ComplexUtility<T[K]> }
: T;
type CachedType<T> = ComplexUtility<T>;
// Reuse instead of recomputing
type UserType = CachedType<User>;
type OrderType = CachedType<Order>;// Bad: Massive single interface
interface MegaInterface {
// ... 1000+ properties
}
// Good: Composed from smaller interfaces
interface CoreData { /* essential props */ }
interface MetaData { /* metadata props */ }
interface ApiData { /* API-related props */ }
type CompleteData = CoreData & MetaData & ApiData;// Cache complex types
type ComplexUtility<T> = T extends object
? { [K in keyof T]: ComplexUtility<T[K]> }
: T;
type CachedType<T> = ComplexUtility<T>;
// Reuse instead of recomputing
type UserType = CachedType<User>;
type OrderType = CachedType<Order>;// Instead of: import lib from 'library' (fails)
import * as lib from 'library';
// Or destructure specific exports
import { specificFunction, SpecificType } from 'library';{
"compilerOptions": {
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}// Instead of: import lib from 'library' (fails)
import * as lib from 'library';
// Or destructure specific exports
import { specificFunction, SpecificType } from 'library';{
"compilerOptions": {
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
}
}// Augment existing module
declare module 'existing-library' {
interface ExistingInterface {
newMethod(): string;
}
export interface NewInterface {
customProp: boolean;
}
}
// Global augmentation
declare global {
interface Window {
customGlobal: {
version: string;
api: {
call(endpoint: string): Promise<any>;
};
};
}
namespace NodeJS {
interface ProcessEnv {
CUSTOM_ENV_VAR: string;
}
}
}// Augment existing module
declare module 'existing-library' {
interface ExistingInterface {
newMethod(): string;
}
export interface NewInterface {
customProp: boolean;
}
}
// Global augmentation
declare global {
interface Window {
customGlobal: {
version: string;
api: {
call(endpoint: string): Promise<any>;
};
};
}
namespace NodeJS {
interface ProcessEnv {
CUSTOM_ENV_VAR: string;
}
}
}// Arithmetic at type level
type Length<T extends readonly unknown[]> = T['length'];
type Head<T extends readonly unknown[]> = T extends readonly [infer H, ...unknown[]] ? H : never;
type Tail<T extends readonly unknown[]> = T extends readonly [unknown, ...infer Rest] ? Rest : [];
// Boolean operations
type And<A extends boolean, B extends boolean> = A extends true
? B extends true ? true : false
: false;
type Or<A extends boolean, B extends boolean> = A extends true
? true
: B extends true ? true : false;
// Tuple manipulation
type Reverse<T extends readonly unknown[]> = T extends readonly [...infer Rest, infer Last]
? [Last, ...Reverse<Rest>]
: [];
// Example: [1, 2, 3] -> [3, 2, 1]
type Reversed = Reverse<[1, 2, 3]>; // [3, 2, 1]// Arithmetic at type level
type Length<T extends readonly unknown[]> = T['length'];
type Head<T extends readonly unknown[]> = T extends readonly [infer H, ...unknown[]] ? H : never;
type Tail<T extends readonly unknown[]> = T extends readonly [unknown, ...infer Rest] ? Rest : [];
// Boolean operations
type And<A extends boolean, B extends boolean> = A extends true
? B extends true ? true : false
: false;
type Or<A extends boolean, B extends boolean> = A extends true
? true
: B extends true ? true : false;
// Tuple manipulation
type Reverse<T extends readonly unknown[]> = T extends readonly [...infer Rest, infer Last]
? [Last, ...Reverse<Rest>]
: [];
// Example: [1, 2, 3] -> [3, 2, 1]
type Reversed = Reverse<[1, 2, 3]>; // [3, 2, 1]// Filter union types
type Filter<T, U> = T extends U ? T : never;
type NonNullable<T> = Filter<T, null | undefined>;
// Map over union types
type StringifyUnion<T> = T extends any ? `${T & string}` : never;
type Status = 'loading' | 'success' | 'error';
type StatusStrings = StringifyUnion<Status>; // "loading" | "success" | "error"
// Partition union types
type Partition<T, U> = [Filter<T, U>, Filter<T, Exclude<T, U>>];
type Values = string | number | boolean;
type [Strings, NonStrings] = Partition<Values, string>; // [string, number | boolean]// Filter union types
type Filter<T, U> = T extends U ? T : never;
type NonNullable<T> = Filter<T, null | undefined>;
// Map over union types
type StringifyUnion<T> = T extends any ? `${T & string}` : never;
type Status = 'loading' | 'success' | 'error';
type StatusStrings = StringifyUnion<Status>; // "loading" | "success" | "error"
// Partition union types
type Partition<T, U> = [Filter<T, U>, Filter<T, Exclude<T, U>>];
type Values = string | number | boolean;
type [Strings, NonStrings] = Partition<Values, string>; // [string, number | boolean]// Deep property path extraction
type PathsToStringProps<T> = T extends string
? []
: {
[K in Extract<keyof T, string>]: T[K] extends string
? [K] | [K, ...PathsToStringProps<T[K]>]
: [K, ...PathsToStringProps<T[K]>];
}[Extract<keyof T, string>];
// Join paths with dots
type Join<K, P> = K extends string | number
? P extends string | number
? `${K}${"" extends P ? "" : "."}${P}`
: never
: never;
type Paths<T> = PathsToStringProps<T> extends infer P
? P extends readonly (string | number)[]
? Join<P[0], Paths<P extends readonly [any, ...infer R] ? R[0] : never>>
: never
: never;
// Example usage
interface User {
name: string;
address: {
street: string;
city: string;
};
}
type UserPaths = Paths<User>; // "name" | "address" | "address.street" | "address.city"// Deep property path extraction
type PathsToStringProps<T> = T extends string
? []
: {
[K in Extract<keyof T, string>]: T[K] extends string
? [K] | [K, ...PathsToStringProps<T[K]>]
: [K, ...PathsToStringProps<T[K]>];
}[Extract<keyof T, string>];
// Join paths with dots
type Join<K, P> = K extends string | number
? P extends string | number
? `${K}${"" extends P ? "" : "."}${P}`
: never
: never;
type Paths<T> = PathsToStringProps<T> extends infer P
? P extends readonly (string | number)[]
? Join<P[0], Paths<P extends readonly [any, ...infer R] ? R[0] : never>>
: never
: never;
// Example usage
interface User {
name: string;
address: {
street: string;
city: string;
};
}
type UserPaths = Paths<User>; // "name" | "address" | "address.street" | "address.city"declare const __brand: unique symbol;
declare const __validator: unique symbol;
interface Brand<T, B extends string> {
readonly [__brand]: B;
readonly [__validator]: (value: T) => boolean;
}
type Branded<T, B extends string> = T & Brand<T, B>;
// Specific branded types
type PositiveNumber = Branded<number, 'PositiveNumber'>;
type EmailAddress = Branded<string, 'EmailAddress'>;
type UserId = Branded<string, 'UserId'>;
// Brand constructors with validation
function createPositiveNumber(value: number): PositiveNumber {
if (value <= 0) {
throw new Error('Number must be positive');
}
return value as PositiveNumber;
}
function createEmailAddress(value: string): EmailAddress {
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
throw new Error('Invalid email format');
}
return value as EmailAddress;
}
// Usage prevents mixing of domain types
function sendEmail(to: EmailAddress, userId: UserId, amount: PositiveNumber) {
// All parameters are type-safe and validated
}
// Error: cannot mix branded types
// sendEmail('invalid@email', 'user123', -100); // Type errorsdeclare const __brand: unique symbol;
declare const __validator: unique symbol;
interface Brand<T, B extends string> {
readonly [__brand]: B;
readonly [__validator]: (value: T) => boolean;
}
type Branded<T, B extends string> = T & Brand<T, B>;
// Specific branded types
type PositiveNumber = Branded<number, 'PositiveNumber'>;
type EmailAddress = Branded<string, 'EmailAddress'>;
type UserId = Branded<string, 'UserId'>;
// Brand constructors with validation
function createPositiveNumber(value: number): PositiveNumber {
if (value <= 0) {
throw new Error('Number must be positive');
}
return value as PositiveNumber;
}
function createEmailAddress(value: string): EmailAddress {
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
throw new Error('Invalid email format');
}
return value as EmailAddress;
}
// Usage prevents mixing of domain types
function sendEmail(to: EmailAddress, userId: UserId, amount: PositiveNumber) {
// All parameters are type-safe and validated
}
// Error: cannot mix branded types
// sendEmail('invalid@email', 'user123', -100); // Type errorsundefinedundefinedundefinedundefined// Prefer interfaces over type intersections for performance
// Bad: Heavy intersection
type HeavyType = TypeA & TypeB & TypeC & TypeD & TypeE;
// Good: Interface extension
interface LightType extends TypeA, TypeB, TypeC, TypeD, TypeE {}
// Use discriminated unions instead of large unions
// Bad: Large union
type Status = 'a' | 'b' | 'c' | /* ... 100 more values */;
// Good: Discriminated union
type Status =
| { category: 'loading'; value: 'pending' | 'in-progress' }
| { category: 'complete'; value: 'success' | 'error' }
| { category: 'cancelled'; value: 'user' | 'timeout' };// Prefer interfaces over type intersections for performance
// Bad: Heavy intersection
type HeavyType = TypeA & TypeB & TypeC & TypeD & TypeE;
// Good: Interface extension
interface LightType extends TypeA, TypeB, TypeC, TypeD, TypeE {}
// Use discriminated unions instead of large unions
// Bad: Large union
type Status = 'a' | 'b' | 'c' | /* ... 100 more values */;
// Good: Discriminated union
type Status =
| { category: 'loading'; value: 'pending' | 'in-progress' }
| { category: 'complete'; value: 'success' | 'error' }
| { category: 'cancelled'; value: 'user' | 'timeout' };undefinedundefinedundefinedundefinedtype-festtype-fest