| name | refactoring-inline-types |
| description | Refactor inline types into reusable, well-organized type definitions using interfaces, type aliases, and generics |
Project configuration: @tsconfig.json @package.json
1. Analyze Current Types
Read the target file specified by the user.
Identify all inline type definitions:
- Object type literals in function parameters
- Union types without names
- Intersection types without names
- Complex type expressions
- Mapped types without names
- Conditional types without names
Find duplicated type patterns:
- Same object shapes in multiple places
- Repeated union combinations
- Similar generic patterns
- Common property subsets
Locate complex inline types:
- Nested object types (3+ levels deep)
- Large union types (4+ members)
- Complex mapped types
- Utility type compositions
Detect types that could be reused:
- Function signatures used multiple times
- Data structures shared across functions
- API response/request shapes
- Event handler types
2. Design Type Structure
Determine appropriate type organization:
Interfaces for object shapes (extensible):
interface User {
id: string
name: string
email: string
}
interface AdminUser extends User {
permissions: string[]
}
Type aliases for unions/primitives/functions:
type Status = "pending" | "active" | "inactive"
type ID = string | number
type Handler = (event: Event) => void
Generics for reusable patterns:
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E }
type Nullable<T> = T | null
type Optional<T> = T | undefined
Utility types for transformations:
type PartialUser = Partial<User>
type UserCredentials = Pick<User, "email" | "password">
type PublicUser = Omit<User, "password">
type ReadonlyUser = Readonly<User>
Plan type hierarchy:
- Base types first
- Derived types after
- Utility types at end
- Group related types together
3. Extract and Refactor
Create types module if needed:
types.tsfor single domaintypes/index.tsfor multiple domainstypes/{domain}.tsfor large projects
Extract inline types to named definitions:
Before:
function createUser(data: {
name: string
email: string
age: number
}): { id: string; name: string; email: string; age: number } {
return { id: generateId(), ...data }
}
After:
interface UserInput {
name: string
email: string
age: number
}
interface User extends UserInput {
id: string
}
function createUser(data: UserInput): User {
return { id: generateId(), ...data }
}
Give descriptive names:
- Follow project conventions
- Use domain language
- Be specific and clear
- Avoid generic names (Data, Info, Params)
Add JSDoc for complex types:
/**
* Represents the result of an async operation.
* Success case includes data, failure case includes error.
*/
type AsyncResult<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E }
Use generic constraints:
interface Repository<T extends { id: string }> {
findById(id: string): Promise<T | null>
save(item: T): Promise<T>
}
Organize types logically:
// Base types
export interface User {
id: string
name: string
}
// Derived types
export interface AdminUser extends User {
permissions: string[]
}
// Input/output types
export type CreateUserInput = Omit<User, "id">
export type UserResponse = Readonly<User>
// Utility types
export type PartialUser = Partial<User>
Export public types:
export interface User { }
export type Status = "active" | "inactive"
Keep internal types private:
interface InternalCache { }
type ValidationState = "valid" | "invalid"
Update original file:
import { User, CreateUserInput, UserResponse } from "./types"
4. Optimization
Replace duplicate types:
- Single source of truth
- Import instead of redefine
- Use extends for variations
Simplify complex inline types:
// Before
function process(
data: { id: string } & ({ type: "user"; name: string } | { type: "admin"; permissions: string[] })
): void { }
// After
interface BaseData {
id: string
}
type UserData = BaseData & {
type: "user"
name: string
}
type AdminData = BaseData & {
type: "admin"
permissions: string[]
}
type ProcessData = UserData | AdminData
function process(data: ProcessData): void { }
Add type aliases for readability:
type UserID = string
type Timestamp = number
type EmailAddress = string
Use discriminated unions:
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; size: number }
| { kind: "rectangle"; width: number; height: number }
function area(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2
case "square":
return shape.size ** 2
case "rectangle":
return shape.width * shape.height
}
}
Apply utility types:
type UserInput = Omit<User, "id" | "createdAt">
type PartialUpdate = Partial<UserInput>
type ReadonlyConfig = Readonly<Config>
type RequiredFields = Required<OptionalConfig>
5. Validation
Run type check on the target file:
pnpm type-check 2>&1 | grep "target-file"
Replace target-file with the actual file path.
Verify:
- No type errors introduced
- Type definitions properly exported/imported
- Refactored code maintains same type safety
- All references updated correctly
If errors found:
- Fix import/export issues
- Correct type definitions
- Update all references
- Re-run validation
Code Quality Requirements:
- MUST use descriptive type names
- MUST add JSDoc for complex types
- MUST follow project naming conventions
- NEVER introduce breaking changes
Extraction Requirements:
- Only extract types that provide value (reusability/clarity)
- Consider discoverability of extracted types
- Maintain logical organization
- Group related types together
Type Design Principles:
- Interfaces for object shapes (extensible)
- Type aliases for unions/primitives/functions
- Generics for reusable patterns
- Utility types to reduce boilerplate
pnpm type-check 2>&1 | grep "target-file"
Replace target-file with the actual file path. Must show zero errors.
File Integrity:
- Verify syntactically valid TypeScript
- Ensure imports/exports correct
- Confirm type definitions accessible
- Verify no runtime behavior changes
Failure Handling:
- Fix type errors immediately
- Update incorrect imports
- Correct type definitions
- Re-run until clean