Advanced Type Operations
Index Types
Application of the keyof Operator:
interface Person {
name: string
age: number
address: string
}
// Get a union type of all object keys
type PersonKeys = keyof Person // "name" | "age" | "address"
// Use Case 1: Restricting Property Access
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const person: Person = { name: 'Alice', age: 30, address: '123 Main St' }
const name = getProperty(person, 'name') // Correct
// const unknown = getProperty(person, 'unknown') // Error: Argument of type '"unknown"' is not assignable to parameter of type '"name" | "age" | "address"'
// Use Case 2: Basis for Mapped Types
type OptionalPerson = {
[K in keyof Person]?: Person[K] // Equivalent to { name?: string; age?: number; address?: string }
}
Advanced Indexed Access Types:
interface User {
id: number
name: string
profile: {
email: string
age: number
}
}
// Deep Indexed Access
type ProfileEmailType = User['profile']['email'] // string
// Combined with Conditional Types
type ValueOf<T> = T[keyof T]
type PersonValues = ValueOf<Person> // string | number
// Utility Type: Get Function Return Type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any
type GreetReturn = ReturnType<() => string> // string
Mapped Types
Basic Mapped Types:
interface Person {
name: string
age: number
address: string
}
// Make all properties optional
type PartialPerson = {
[K in keyof Person]?: Person[K]
}
// Make all properties readonly
type ReadonlyPerson = {
readonly [K in keyof Person]: Person[K]
}
// Change all property types to string
type StringifiedPerson = {
[K in keyof Person]: string
}
Advanced Mapped Types:
// Conditional Mapping: Filter Specific Type Properties
type StringKeys<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K]
}
type PersonStringProps = StringKeys<Person> // { name: string; address: string }
// Key Name Transformation: Add Prefix
type AddPrefix<T, Prefix extends string> = {
[K in keyof T as `${Prefix}${Capitalize<string & K>}`]: T[K]
}
type PrefixedPerson = AddPrefix<Person, 'user'> // { userName: string; userAge: number; userAddress: string }
// Property Filtering
type FilterProperties<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K]
}
type NumberProps = FilterProperties<Person, number> // { age: number }
Conditional Types
Basic Conditional Types:
// Simple Conditional Type
type IsString<T> = T extends string ? true : false
type A = IsString<'hello'> // true
type B = IsString<123> // false
// Distributed Conditional Types (when T is a union type)
type ToArray<T> = T extends any ? T[] : never
type StrOrNumArray = ToArray<string | number> // string[] | number[]
// Non-Distributed Conditional Types (using square brackets)
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never
type StrOrNumArrayNonDist = ToArrayNonDist<string | number> // (string | number)[]
Application of the infer Keyword:
// Extract Function Return Type
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any
type GreetReturn = ReturnType<() => string> // string
// Extract Array Element Type
type ElementType<T> = T extends (infer U)[] ? U : T
type NumArrayElement = ElementType<number[]> // number
type StrElement = ElementType<string> // string
// Extract Promise Generic Type
type UnpackPromise<T> = T extends Promise<infer U> ? U : T
type PromiseString = UnpackPromise<Promise<string>> // string
// Recursively Unpack Nested Promises
type DeepUnpackPromise<T> = T extends Promise<infer U> ? DeepUnpackPromise<U> : T
type DeepPromise = DeepUnpackPromise<Promise<Promise<Promise<string>>>> // string
Type Inference (infer)
Complex Type Inference Cases:
// Extract Function Parameter Types
type Parameters<T> = T extends (...args: infer P) => any ? P : never
type GreetParams = Parameters<() => void> // []
type AddParams = Parameters<(a: number, b: number) => number> // [number, number]
// Extract Constructor Parameters
type ConstructorParameters<T extends new (...args: any) => any> =
T extends new (...args: infer P) => any ? P : never
class Person {
constructor(public name: string, public age: number) {}
}
type PersonCtorParams = ConstructorParameters<typeof Person> // [string, number]
// Extract Class Instance Type
type InstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer R ? R : any
type PersonInstance = InstanceType<typeof Person> // Person
// Recursive Handling of Nested Structures
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}
interface NestedObject {
a: number
b: {
c: string
d: {
e: boolean
}
}
}
type PartialNested = DeepPartial<NestedObject>
Template Literal Types
String Template Types:
// Basic Template Literal
type EventName = 'click' | 'scroll' | 'mousemove'
type HandlerName = `on${Capitalize<EventName>}`
// "onClick" | "onScroll" | "onMousemove"
// Dynamic API Paths
type ApiRoute = '/api' | '/user' | '/product'
type FullApiPath = `/v1${ApiRoute}`
// "/v1/api" | "/v1/user" | "/v1/product"
// CSS Unit Conversion
type PxValue = `${number}px`
type PercentValue = `${number}%`
type CssUnit = PxValue | PercentValue
// "1px" | "2px" | ... | "100px" | "0%" | "1%" | ... | "100%"
// Combining Multiple Templates
type Direction = 'North' | 'South' | 'East' | 'West'
type CompassPoint = `to${Capitalize<Direction>}`
// "toNorth" | "toSouth" | "toEast" | "toWest"
Advanced Template Applications:
// Database Field Type Mapping
type FieldType = 'string' | 'number' | 'boolean'
type ColumnDef<T extends FieldType> = `column_${T}`
type StringColumn = ColumnDef<'string'> // "column_string"
type NumberColumn = ColumnDef<'number'> // "column_number"
// RESTful Method Types
type HttpMethod = 'get' | 'post' | 'put' | 'delete'
type ApiMethod = `_${HttpMethod}`
type GetMethod = ApiMethod // "_get" | "_post" | "_put" | "_delete"
// State Machine Transitions
type State = 'idle' | 'loading' | 'success' | 'error'
type Transition<T extends State> = `${T}_to_${State}`
type IdleToLoading = Transition<'idle'> // "idle_to_idle" | "idle_to_loading" | "idle_to_success" | "idle_to_error"



