← TypeScript EnglishChapter 10 of 12

Advanced Types

## Learning Objectives - Master mapped types - Understand conditional types - Use template literal types - Create utility types - Apply infer keyword ## Mapped Types ### Basic Syntax ```typescript type Readonly = { readonly [P in keyof T]: T[P]; }; type Optional = { [P in keyof T]?: T[P]; }; ``` ### Example: All Properties Optional ```typescript interface User { id: number; name: string; email: string; } type PartialUser = Partial; // { id?: number; name?: string; email?: string } ``` ### Example: All Properties Required ```typescript type Required = { [P in keyof T]-?: T[P]; }; type RequiredUser = Required; // Restores all required properties ``` ## Record Type ### Create Object Type ```typescript type Role = "admin" | "user" | "guest"; type Permissions = Record; let perms: Permissions = { admin: true, user: false, guest: true }; ``` ### Record with Complex Values ```typescript type EntityMap = Record; let users: EntityMap = { "user1": { id: 1, name: "Alice" }, "user2": { id: 2, name: "Bob" } }; ``` ## Conditional Types ### Conditional Types Basic Syntax ```typescript T extends U ? X : Y ``` ### Example ```typescript type IsString = T extends string ? true : false; type A = IsString; // true type B = IsString; // false ``` ### With Union ```typescript type ToArray = T extends any ? T[] : never; type Strings = ToArray; // string[] type Numbers = ToArray; // number[] type Mixed = ToArray; // string[] | number[] ``` ## Distributive Conditional Types ### Applied to Unions ```typescript type ToArray = T extends any ? T[] : never; // string | number becomes string[] | number[] type Result = ToArray; // = string[] | number[] ``` ### Prevent Distribution ```typescript type ToArrayNonDist = [T] extends [any] ? T[] : never; // Single array: (string | number)[] type Result = ToArrayNonDist; ``` ## infer Keyword ### Extract Type ```typescript type ReturnType = T extends (...args: any[]) => infer R ? R : never; function getUser(): User { return { name: "Alice" }; } type R = ReturnType; // User ``` ### Extract Element Type ```typescript type ElementType = T extends (infer E)[] ? E : never; type N = ElementType; // number type S = ElementType; // string ``` ## Template Literal Types ### Basic ```typescript type World = "world"; type Greeting = `hello ${World}`; // "hello world" ``` ### Template Literals With Union ```typescript type Direction = "top" | "left"; type EventName = `on${Capitalize = { [P in keyof T as `get${Capitalize}`]: () => T[P] }; interface User { name: string; age: number; } type UserGetters = Getters; // { getName: () => string; getAge: () => number } ``` ## Utility Types Deep Dive ### Readonly ```typescript type Readonly = { readonly [P in keyof T]: T[P]; }; interface Config { host: string; port: number; } type ImmutableConfig = Readonly; ``` ### Partial ```typescript type Partial = { [P in keyof T]?: T[P]; }; function updateUser(id: number, updates: Partial): void { // updates can have any subset of User properties } ``` ### Required ```typescript type Required = { [P in keyof T]-?: T[P]; }; // Removes optional marker ``` ### Pick ```typescript type Pick = { [P in K]: T[P]; }; type UserPreview = Pick; ``` ### Omit ```typescript type Omit = Pick>; type UserWithoutEmail = Omit; ``` ### Exclude ```typescript type Exclude = T extends U ? never : T; type T = string | number | null; type NonNullable = Exclude; // string | number ``` ### Extract ```typescript type Extract = T extends U ? T : never; type T = string | number | boolean; type Numeric = Extract; // string | number ``` ### NonNullable ```typescript type NonNullable = Exclude; type T = string | null | undefined; type U = NonNullable; // string ``` ### ReturnType ```typescript type ReturnType = T extends (...args: any[]) => infer R ? R : any; function createUser() { return { name: "Alice", age: 30 }; } type User = ReturnType; ``` ### Parameters ```typescript type Parameters = T extends (...args: infer P) => any ? P : never; function greet(name: string, age: number): string { return `Hello ${name}`; } type GreetParams = Parameters; // [name: string, age: number] ``` ## Recursive Types ### Deep Partial ```typescript type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; }; interface Company { name: string; address: { street: string; city: string; }; } // All nested properties optional type OptionalCompany = DeepPartial; ``` ## Indexed Access Types ### Get Type of Property ```typescript type User = { name: string; age: number; }; type Name = User["name"]; // string ``` ### Indexed Access With Union ```typescript type User = { name: string; age: number; email: string; }; type NameOrEmail = User["name" | "email"]; // string ``` ### keyof with Indexed ```typescript type User = { id: number; name: string; }; type UserKeys = User[keyof User]; // number | string ``` ## Unwrap Types ### Promise Unwrap ```typescript type Awaited = T extends Promise ? U : T; type A = Awaited>; // string type B = Awaited; // number ``` ### Array Element ```typescript type ArrayElement = T extends (infer E)[] ? E : never; type E = ArrayElement; // string ``` ## Summary - Mapped types: `[P in keyof T]` transforms properties - Conditional types: `T extends U ? X : Y` - Template literals: `` `prefix${T}suffix` `` - `infer` extracts types within conditional - Utility types use mapped and conditional types - `keyof` gets union of object keys - Recursive types for deep transformations - Indexed access: `T["property"]`

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →