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 →