or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aliases-guards.mdflow-utilities.mdindex.mdmapped-types.md

mapped-types.mddocs/

0

# Advanced Mapped Types

1

2

Advanced mapped types provide sophisticated type transformations for object manipulation, key selection, property filtering, and complex type operations. These utilities enable powerful compile-time type transformations for building type-safe applications.

3

4

## Import

5

6

```typescript

7

import {

8

// Set operations

9

SetIntersection, SetDifference, SetComplement, SymmetricDifference,

10

11

// Object manipulation

12

Omit, Optional, Required, Diff, Subtract, Overwrite, Assign,

13

Intersection, PickByValue, PickByValueExact, OmitByValue, OmitByValueExact,

14

15

// Key selection

16

FunctionKeys, NonFunctionKeys, MutableKeys, WritableKeys, ReadonlyKeys,

17

RequiredKeys, OptionalKeys,

18

19

// Advanced utilities

20

NonUndefined, Unionize, PromiseType, Brand, Exact, ValuesType, UnionToIntersection,

21

Mutable, Writable,

22

23

// Deep transformations

24

DeepReadonly, DeepRequired, DeepNonNullable, DeepPartial

25

} from 'utility-types';

26

```

27

28

For CommonJS:

29

30

```javascript

31

const {

32

// Set operations

33

SetIntersection, SetDifference, SetComplement, SymmetricDifference,

34

35

// Object manipulation

36

Omit, Optional, Required, Diff, Subtract, Overwrite, Assign,

37

Intersection, PickByValue, PickByValueExact, OmitByValue, OmitByValueExact,

38

39

// Key selection

40

FunctionKeys, NonFunctionKeys, MutableKeys, WritableKeys, ReadonlyKeys,

41

RequiredKeys, OptionalKeys,

42

43

// Advanced utilities

44

NonUndefined, Unionize, PromiseType, Brand, Exact, ValuesType, UnionToIntersection,

45

Mutable, Writable,

46

47

// Deep transformations

48

DeepReadonly, DeepRequired, DeepNonNullable, DeepPartial

49

} = require('utility-types');

50

```

51

52

## Set Operations

53

54

### SetIntersection

55

56

Get the intersection of two union types (same as Extract).

57

58

```typescript { .api }

59

type SetIntersection<A, B> = A extends B ? A : never;

60

```

61

62

**Usage:**

63

64

```typescript

65

type Colors = 'red' | 'green' | 'blue';

66

type Warm = 'red' | 'orange' | 'yellow';

67

68

type WarmColors = SetIntersection<Colors, Warm>;

69

// Result: 'red'

70

71

type StringOrNumber = string | number;

72

type NumberOrBoolean = number | boolean;

73

74

type CommonType = SetIntersection<StringOrNumber, NumberOrBoolean>;

75

// Result: number

76

77

// With function types

78

type AsyncFunction = () => Promise<any>;

79

type SyncFunction = () => any;

80

81

type AsyncFromMixed = SetIntersection<AsyncFunction | SyncFunction, Function>;

82

// Result: () => Promise<any> | () => any

83

```

84

85

### SetDifference

86

87

Get the difference between two union types (same as Exclude).

88

89

```typescript { .api }

90

type SetDifference<A, B> = A extends B ? never : A;

91

```

92

93

**Usage:**

94

95

```typescript

96

type AllTypes = string | number | boolean | null;

97

type TruthyTypes = string | number | boolean;

98

99

type FalsyTypes = SetDifference<AllTypes, TruthyTypes>;

100

// Result: null

101

102

type Events = 'click' | 'focus' | 'blur' | 'keydown';

103

type MouseEvents = 'click' | 'mousedown' | 'mouseup';

104

105

type NonMouseEvents = SetDifference<Events, MouseEvents>;

106

// Result: 'focus' | 'blur' | 'keydown'

107

```

108

109

### SetComplement

110

111

Get the complement of a subset within a superset.

112

113

```typescript { .api }

114

type SetComplement<A, A1 extends A> = SetDifference<A, A1>;

115

```

116

117

**Usage:**

118

119

```typescript

120

type AllPermissions = 'read' | 'write' | 'delete' | 'admin';

121

type UserPermissions = 'read' | 'write';

122

123

type MissingPermissions = SetComplement<AllPermissions, UserPermissions>;

124

// Result: 'delete' | 'admin'

125

126

// Useful for ensuring exhaustive handling

127

function handleRemainingCases(permission: SetComplement<AllPermissions, 'read' | 'write'>) {

128

// permission is typed as 'delete' | 'admin'

129

switch (permission) {

130

case 'delete':

131

return handleDelete();

132

case 'admin':

133

return handleAdmin();

134

}

135

}

136

```

137

138

### SymmetricDifference

139

140

Get the symmetric difference of two union types.

141

142

```typescript { .api }

143

type SymmetricDifference<A, B> = SetDifference<A | B, A & B>;

144

```

145

146

**Usage:**

147

148

```typescript

149

type SetA = 'a' | 'b' | 'c';

150

type SetB = 'b' | 'c' | 'd';

151

152

type OnlyInAOrB = SymmetricDifference<SetA, SetB>;

153

// Result: 'a' | 'd'

154

155

type Frontend = 'react' | 'vue' | 'angular';

156

type Backend = 'node' | 'django' | 'rails' | 'vue';

157

158

type ExclusiveTechs = SymmetricDifference<Frontend, Backend>;

159

// Result: 'react' | 'angular' | 'node' | 'django' | 'rails'

160

```

161

162

## Object Manipulation

163

164

### Omit

165

166

Remove specified properties from an object type.

167

168

```typescript { .api }

169

type Omit<T, K extends keyof any> = Pick<T, SetDifference<keyof T, K>>;

170

```

171

172

**Usage:**

173

174

```typescript

175

interface User {

176

id: number;

177

name: string;

178

email: string;

179

password: string;

180

createdAt: Date;

181

}

182

183

type PublicUser = Omit<User, 'password'>;

184

// Result: { id: number; name: string; email: string; createdAt: Date; }

185

186

type UserSummary = Omit<User, 'password' | 'createdAt'>;

187

// Result: { id: number; name: string; email: string; }

188

189

// Works with union types

190

type ApiResponse =

191

| { type: 'success'; data: any; timestamp: number }

192

| { type: 'error'; message: string; timestamp: number };

193

194

type ResponseWithoutTimestamp = Omit<ApiResponse, 'timestamp'>;

195

// Result: { type: 'success'; data: any } | { type: 'error'; message: string }

196

```

197

198

### Optional

199

200

Make specified properties optional.

201

202

```typescript { .api }

203

type Optional<T extends object, K extends keyof T = keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

204

```

205

206

**Usage:**

207

208

```typescript

209

interface CreateUserRequest {

210

name: string;

211

email: string;

212

age: number;

213

avatar: string;

214

}

215

216

type CreateUserWithDefaults = Optional<CreateUserRequest, 'age' | 'avatar'>;

217

// Result: { name: string; email: string; age?: number; avatar?: string; }

218

219

// Make all properties optional

220

type PartialUser = Optional<CreateUserRequest>;

221

// Result: { name?: string; email?: string; age?: number; avatar?: string; }

222

223

function createUser(data: CreateUserWithDefaults) {

224

const user = {

225

...data,

226

age: data.age ?? 18,

227

avatar: data.avatar ?? '/default-avatar.png'

228

};

229

return user;

230

}

231

```

232

233

### Required (AugmentedRequired)

234

235

Make specified properties required.

236

237

```typescript { .api }

238

type Required<T extends object, K extends keyof T = keyof T> = Omit<T, K> & Required<Pick<T, K>>;

239

```

240

241

**Usage:**

242

243

```typescript

244

interface PartialConfig {

245

host?: string;

246

port?: number;

247

timeout?: number;

248

retries?: number;

249

}

250

251

type RequiredConfig = Required<PartialConfig, 'host' | 'port'>;

252

// Result: { host: string; port: number; timeout?: number; retries?: number; }

253

254

// Make all properties required

255

type FullConfig = Required<PartialConfig>;

256

// Result: { host: string; port: number; timeout: number; retries: number; }

257

258

function connect(config: RequiredConfig) {

259

// host and port are guaranteed to exist

260

console.log(`Connecting to ${config.host}:${config.port}`);

261

}

262

```

263

264

### Diff

265

266

Remove properties that exist in the second type from the first type.

267

268

```typescript { .api }

269

type Diff<T extends object, U extends object> = Pick<T, SetDifference<keyof T, keyof U>>;

270

```

271

272

**Usage:**

273

274

```typescript

275

interface ExtendedUser {

276

id: number;

277

name: string;

278

email: string;

279

password: string;

280

isAdmin: boolean;

281

lastLogin: Date;

282

}

283

284

interface BasicUser {

285

id: number;

286

name: string;

287

email: string;

288

}

289

290

type UserExtensions = Diff<ExtendedUser, BasicUser>;

291

// Result: { password: string; isAdmin: boolean; lastLogin: Date; }

292

293

// Common pattern: finding unique properties

294

interface ComponentProps {

295

className?: string;

296

style?: React.CSSProperties;

297

children?: React.ReactNode;

298

onClick: () => void;

299

disabled: boolean;

300

}

301

302

interface HTMLButtonProps {

303

className?: string;

304

style?: React.CSSProperties;

305

children?: React.ReactNode;

306

disabled?: boolean;

307

}

308

309

type CustomProps = Diff<ComponentProps, HTMLButtonProps>;

310

// Result: { onClick: () => void; disabled: boolean; }

311

```

312

313

### PickByValue

314

315

Pick properties from an object type based on their value types.

316

317

```typescript { .api }

318

type PickByValue<T, ValueType> = Pick<T, {

319

[Key in keyof T]: T[Key] extends ValueType ? Key : never;

320

}[keyof T]>;

321

```

322

323

**Usage:**

324

325

```typescript

326

interface MixedData {

327

id: number;

328

name: string;

329

count: number;

330

active: boolean;

331

tags: string[];

332

metadata: Record<string, any>;

333

}

334

335

type StringFields = PickByValue<MixedData, string>;

336

// Result: { name: string; }

337

338

type NumberFields = PickByValue<MixedData, number>;

339

// Result: { id: number; count: number; }

340

341

type ArrayFields = PickByValue<MixedData, any[]>;

342

// Result: { tags: string[]; }

343

344

// Useful for creating type-safe field selectors

345

function getStringFields<T>(obj: T): PickByValue<T, string> {

346

const result = {} as any;

347

for (const [key, value] of Object.entries(obj)) {

348

if (typeof value === 'string') {

349

result[key] = value;

350

}

351

}

352

return result;

353

}

354

```

355

356

### OmitByValue

357

358

Remove properties from an object type based on their value types.

359

360

```typescript { .api }

361

type OmitByValue<T, ValueType> = Pick<T, {

362

[Key in keyof T]: T[Key] extends ValueType ? never : Key;

363

}[keyof T]>;

364

```

365

366

**Usage:**

367

368

```typescript

369

interface UserData {

370

id: number;

371

name: string;

372

email: string;

373

isActive: boolean;

374

loginCount: number;

375

settings: Record<string, any>;

376

}

377

378

type NonStringFields = OmitByValue<UserData, string>;

379

// Result: { id: number; isActive: boolean; loginCount: number; settings: Record<string, any>; }

380

381

type NonNumberFields = OmitByValue<UserData, number>;

382

// Result: { name: string; email: string; isActive: boolean; settings: Record<string, any>; }

383

384

// Remove function properties

385

interface EventHandler {

386

name: string;

387

type: string;

388

handler: () => void;

389

cleanup: () => void;

390

priority: number;

391

}

392

393

type EventData = OmitByValue<EventHandler, Function>;

394

// Result: { name: string; type: string; priority: number; }

395

```

396

397

## Key Selection

398

399

### FunctionKeys

400

401

Get keys of properties that are functions.

402

403

```typescript { .api }

404

type FunctionKeys<T extends object> = {

405

[K in keyof T]-?: NonUndefined<T[K]> extends Function ? K : never;

406

}[keyof T];

407

```

408

409

**Usage:**

410

411

```typescript

412

class UserService {

413

name: string = 'UserService';

414

version: number = 1;

415

416

getUser(id: number): User { return {} as User; }

417

createUser(data: CreateUserData): User { return {} as User; }

418

deleteUser(id: number): void {}

419

}

420

421

type UserServiceMethods = FunctionKeys<UserService>;

422

// Result: 'getUser' | 'createUser' | 'deleteUser'

423

424

// Create method-only interface

425

type UserServiceInterface = Pick<UserService, FunctionKeys<UserService>>;

426

// Result: {

427

// getUser(id: number): User;

428

// createUser(data: CreateUserData): User;

429

// deleteUser(id: number): void;

430

// }

431

```

432

433

### NonFunctionKeys

434

435

Get keys of properties that are not functions.

436

437

```typescript { .api }

438

type NonFunctionKeys<T extends object> = {

439

[K in keyof T]-?: NonUndefined<T[K]> extends Function ? never : K;

440

}[keyof T];

441

```

442

443

**Usage:**

444

445

```typescript

446

class DatabaseConnection {

447

host: string = 'localhost';

448

port: number = 5432;

449

isConnected: boolean = false;

450

451

connect(): Promise<void> { return Promise.resolve(); }

452

disconnect(): void {}

453

query(sql: string): Promise<any[]> { return Promise.resolve([]); }

454

}

455

456

type ConnectionData = NonFunctionKeys<DatabaseConnection>;

457

// Result: 'host' | 'port' | 'isConnected'

458

459

type ConnectionState = Pick<DatabaseConnection, NonFunctionKeys<DatabaseConnection>>;

460

// Result: { host: string; port: number; isConnected: boolean; }

461

```

462

463

### RequiredKeys

464

465

Get keys of properties that are required (not optional).

466

467

```typescript { .api }

468

type RequiredKeys<T> = {

469

[K in keyof T]: {} extends Pick<T, K> ? never : K;

470

}[keyof T];

471

```

472

473

**Usage:**

474

475

```typescript

476

interface UserProfile {

477

id: number;

478

name: string;

479

email?: string;

480

avatar?: string;

481

bio?: string;

482

}

483

484

type RequiredUserFields = RequiredKeys<UserProfile>;

485

// Result: 'id' | 'name'

486

487

type MinimalUser = Pick<UserProfile, RequiredKeys<UserProfile>>;

488

// Result: { id: number; name: string; }

489

490

// Useful for validation

491

function validateRequiredFields<T>(obj: Partial<T>): obj is Pick<T, RequiredKeys<T>> {

492

// Implementation would check if all required fields are present

493

return true; // Simplified

494

}

495

```

496

497

### OptionalKeys

498

499

Get keys of properties that are optional.

500

501

```typescript { .api }

502

type OptionalKeys<T> = {

503

[K in keyof T]: {} extends Pick<T, K> ? K : never;

504

}[keyof T];

505

```

506

507

**Usage:**

508

509

```typescript

510

interface CreatePostRequest {

511

title: string;

512

content: string;

513

tags?: string[];

514

publishedAt?: Date;

515

featuredImage?: string;

516

}

517

518

type OptionalPostFields = OptionalKeys<CreatePostRequest>;

519

// Result: 'tags' | 'publishedAt' | 'featuredImage'

520

521

type PostDefaults = Pick<CreatePostRequest, OptionalKeys<CreatePostRequest>>;

522

// Result: { tags?: string[]; publishedAt?: Date; featuredImage?: string; }

523

524

function applyDefaults(request: CreatePostRequest): Required<CreatePostRequest> {

525

return {

526

...request,

527

tags: request.tags ?? [],

528

publishedAt: request.publishedAt ?? new Date(),

529

featuredImage: request.featuredImage ?? '/default-image.jpg'

530

};

531

}

532

```

533

534

## Advanced Utilities

535

536

### UnionToIntersection

537

538

Convert a union type to an intersection type.

539

540

```typescript { .api }

541

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;

542

```

543

544

**Usage:**

545

546

```typescript

547

type A = { a: string };

548

type B = { b: number };

549

type C = { c: boolean };

550

551

type Union = A | B | C;

552

type Intersection = UnionToIntersection<Union>;

553

// Result: { a: string } & { b: number } & { c: boolean }

554

// Which is equivalent to: { a: string; b: number; c: boolean }

555

556

// Useful for combining multiple object types

557

interface BaseConfig { timeout: number; }

558

interface AuthConfig { apiKey: string; }

559

interface CacheConfig { cacheSize: number; }

560

561

type ConfigUnion = BaseConfig | AuthConfig | CacheConfig;

562

type FullConfig = UnionToIntersection<ConfigUnion>;

563

// Result: { timeout: number; apiKey: string; cacheSize: number; }

564

```

565

566

### Brand

567

568

Create a branded (nominal) type to distinguish values of the same underlying type.

569

570

```typescript { .api }

571

type Brand<T, U> = T & { __brand: U };

572

```

573

574

**Usage:**

575

576

```typescript

577

type UserId = Brand<number, 'UserId'>;

578

type ProductId = Brand<number, 'ProductId'>;

579

580

function getUser(id: UserId): User {

581

// Implementation

582

return {} as User;

583

}

584

585

function getProduct(id: ProductId): Product {

586

// Implementation

587

return {} as Product;

588

}

589

590

declare const userId: UserId;

591

declare const productId: ProductId;

592

593

getUser(userId); // OK

594

getProduct(productId); // OK

595

596

// getUser(productId); // Error: ProductId is not assignable to UserId

597

// getProduct(userId); // Error: UserId is not assignable to ProductId

598

599

// Creating branded values

600

function createUserId(id: number): UserId {

601

return id as UserId;

602

}

603

604

function createProductId(id: number): ProductId {

605

return id as ProductId;

606

}

607

608

const safeUserId = createUserId(123);

609

const safeProductId = createProductId(456);

610

```

611

612

### Exact

613

614

Create a branded object type for exact type matching.

615

616

```typescript { .api }

617

type Exact<A extends object> = A & { __brand: keyof A };

618

```

619

620

**Usage:**

621

622

```typescript

623

interface User {

624

id: number;

625

name: string;

626

}

627

628

type ExactUser = Exact<User>;

629

630

// Useful for ensuring exact object shapes

631

function processExactUser(user: ExactUser): void {

632

// Implementation

633

}

634

635

// This creates an exact match requirement

636

const user: ExactUser = { id: 1, name: 'Alice' } as ExactUser;

637

processExactUser(user);

638

639

// Note: This is primarily for advanced type-level programming

640

// Most applications should use regular TypeScript structural typing

641

```

642

643

### PromiseType

644

645

Extract the resolved type from a Promise type.

646

647

```typescript { .api }

648

type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never;

649

```

650

651

**Usage:**

652

653

```typescript

654

async function fetchUser(id: number): Promise<{ name: string; email: string }> {

655

// Implementation

656

return { name: 'User', email: 'user@example.com' };

657

}

658

659

type UserType = PromiseType<ReturnType<typeof fetchUser>>;

660

// Result: { name: string; email: string }

661

662

// With generic promises

663

type StringPromise = Promise<string>;

664

type NumberArrayPromise = Promise<number[]>;

665

666

type StringType = PromiseType<StringPromise>; // Result: string

667

type NumberArrayType = PromiseType<NumberArrayPromise>; // Result: number[]

668

669

// Useful for working with async function types

670

function handleAsyncResult<T extends Promise<any>>(

671

promise: T,

672

callback: (result: PromiseType<T>) => void

673

) {

674

promise.then(callback);

675

}

676

```

677

678

### ValuesType

679

680

Get the union type of all values in an array, object, or array-like structure.

681

682

```typescript { .api }

683

type ValuesType<T extends ReadonlyArray<any> | ArrayLike<any> | Record<any, any>> =

684

T extends ReadonlyArray<any>

685

? T[number]

686

: T extends ArrayLike<any>

687

? T[number]

688

: T extends object

689

? T[keyof T]

690

: never;

691

```

692

693

**Usage:**

694

695

```typescript

696

// With arrays

697

const colors = ['red', 'green', 'blue'] as const;

698

type Color = ValuesType<typeof colors>;

699

// Result: 'red' | 'green' | 'blue'

700

701

// With objects

702

const statusCodes = {

703

OK: 200,

704

NOT_FOUND: 404,

705

SERVER_ERROR: 500

706

} as const;

707

708

type StatusCode = ValuesType<typeof statusCodes>;

709

// Result: 200 | 404 | 500

710

711

// With tuples

712

type UserTuple = [string, number, boolean];

713

type TupleValues = ValuesType<UserTuple>;

714

// Result: string | number | boolean

715

716

// Practical example

717

const eventTypes = {

718

CLICK: 'click',

719

FOCUS: 'focus',

720

BLUR: 'blur'

721

} as const;

722

723

type EventType = ValuesType<typeof eventTypes>;

724

725

function handleEvent(type: EventType) {

726

// type is 'click' | 'focus' | 'blur'

727

switch (type) {

728

case 'click':

729

// Handle click

730

break;

731

case 'focus':

732

// Handle focus

733

break;

734

case 'blur':

735

// Handle blur

736

break;

737

}

738

}

739

```

740

741

## Deep Transformations

742

743

### DeepReadonly

744

745

Recursively make all properties readonly, including nested objects and arrays.

746

747

```typescript { .api }

748

type DeepReadonly<T> = T extends ((...args: any[]) => any) | Primitive

749

? T

750

: T extends _DeepReadonlyArray<infer U>

751

? _DeepReadonlyArray<U>

752

: T extends _DeepReadonlyObject<infer V>

753

? _DeepReadonlyObject<V>

754

: T;

755

756

interface _DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}

757

type _DeepReadonlyObject<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> };

758

```

759

760

**Usage:**

761

762

```typescript

763

interface NestedConfig {

764

server: {

765

host: string;

766

port: number;

767

ssl: {

768

enabled: boolean;

769

cert: string;

770

key: string;

771

};

772

};

773

database: {

774

hosts: string[];

775

credentials: {

776

username: string;

777

password: string;

778

};

779

};

780

}

781

782

type ReadonlyConfig = DeepReadonly<NestedConfig>;

783

// All properties at every level become readonly:

784

// {

785

// readonly server: {

786

// readonly host: string;

787

// readonly port: number;

788

// readonly ssl: {

789

// readonly enabled: boolean;

790

// readonly cert: string;

791

// readonly key: string;

792

// };

793

// };

794

// readonly database: {

795

// readonly hosts: readonly string[];

796

// readonly credentials: {

797

// readonly username: string;

798

// readonly password: string;

799

// };

800

// };

801

// }

802

803

function processConfig(config: ReadonlyConfig) {

804

// config.server.host = 'new-host'; // Error: Cannot assign to readonly property

805

// config.database.hosts.push('new-host'); // Error: hosts is readonly array

806

console.log(config.server.host); // OK: reading is allowed

807

}

808

```

809

810

### DeepRequired

811

812

Recursively make all properties required, including nested objects and arrays.

813

814

```typescript { .api }

815

type DeepRequired<T> = T extends (...args: any[]) => any

816

? T

817

: T extends any[]

818

? _DeepRequiredArray<T[number]>

819

: T extends object

820

? _DeepRequiredObject<T>

821

: T;

822

823

interface _DeepRequiredArray<T> extends Array<DeepRequired<NonUndefined<T>>> {}

824

type _DeepRequiredObject<T> = { [P in keyof T]-?: DeepRequired<NonUndefined<T[P]>> };

825

```

826

827

**Usage:**

828

829

```typescript

830

interface PartialUser {

831

id?: number;

832

profile?: {

833

name?: string;

834

email?: string;

835

settings?: {

836

theme?: 'light' | 'dark';

837

notifications?: boolean;

838

};

839

};

840

posts?: Array<{

841

title?: string;

842

content?: string;

843

}>;

844

}

845

846

type CompleteUser = DeepRequired<PartialUser>;

847

// All properties at every level become required:

848

// {

849

// id: number;

850

// profile: {

851

// name: string;

852

// email: string;

853

// settings: {

854

// theme: 'light' | 'dark';

855

// notifications: boolean;

856

// };

857

// };

858

// posts: Array<{

859

// title: string;

860

// content: string;

861

// }>;

862

// }

863

864

function validateCompleteUser(user: unknown): user is CompleteUser {

865

// Validation logic that ensures all nested properties exist

866

return true; // Simplified

867

}

868

```

869

870

### DeepPartial

871

872

Recursively make all properties optional, including nested objects and arrays.

873

874

```typescript { .api }

875

type DeepPartial<T> = { [P in keyof T]?: _DeepPartial<T[P]> };

876

877

type _DeepPartial<T> = T extends Function

878

? T

879

: T extends Array<infer U>

880

? _DeepPartialArray<U>

881

: T extends object

882

? DeepPartial<T>

883

: T | undefined;

884

885

interface _DeepPartialArray<T> extends Array<_DeepPartial<T>> {}

886

```

887

888

**Usage:**

889

890

```typescript

891

interface StrictUser {

892

id: number;

893

profile: {

894

name: string;

895

email: string;

896

address: {

897

street: string;

898

city: string;

899

country: string;

900

};

901

};

902

preferences: {

903

theme: 'light' | 'dark';

904

language: string;

905

notifications: {

906

email: boolean;

907

push: boolean;

908

};

909

};

910

}

911

912

type FlexibleUserUpdate = DeepPartial<StrictUser>;

913

// All properties at every level become optional:

914

// {

915

// id?: number;

916

// profile?: {

917

// name?: string;

918

// email?: string;

919

// address?: {

920

// street?: string;

921

// city?: string;

922

// country?: string;

923

// };

924

// };

925

// preferences?: {

926

// theme?: 'light' | 'dark';

927

// language?: string;

928

// notifications?: {

929

// email?: boolean;

930

// push?: boolean;

931

// };

932

// };

933

// }

934

935

function updateUser(id: number, updates: FlexibleUserUpdate) {

936

// Any combination of nested properties can be provided

937

}

938

939

// Usage examples:

940

updateUser(1, { profile: { name: 'Alice' } });

941

updateUser(2, { preferences: { notifications: { email: false } } });

942

updateUser(3, { profile: { address: { city: 'New York' } } });

943

```

944

945

### DeepNonNullable

946

947

Recursively remove null and undefined from all properties, including nested structures.

948

949

```typescript { .api }

950

type DeepNonNullable<T> = T extends (...args: any[]) => any

951

? T

952

: T extends any[]

953

? _DeepNonNullableArray<T[number]>

954

: T extends object

955

? _DeepNonNullableObject<T>

956

: T;

957

958

interface _DeepNonNullableArray<T> extends Array<DeepNonNullable<NonNullable<T>>> {}

959

type _DeepNonNullableObject<T> = { [P in keyof T]-?: DeepNonNullable<NonNullable<T[P]>> };

960

```

961

962

**Usage:**

963

964

```typescript

965

interface NullableData {

966

id: number | null;

967

user: {

968

name: string | null;

969

email?: string | null;

970

profile: {

971

avatar: string | null | undefined;

972

bio: string | null;

973

} | null;

974

} | null;

975

tags: Array<string | null> | null;

976

}

977

978

type CleanData = DeepNonNullable<NullableData>;

979

// All null and undefined are removed at every level:

980

// {

981

// id: number;

982

// user: {

983

// name: string;

984

// email: string;

985

// profile: {

986

// avatar: string;

987

// bio: string;

988

// };

989

// };

990

// tags: Array<string>;

991

// }

992

993

function processCleanData(data: CleanData) {

994

// All properties are guaranteed to be non-null/non-undefined

995

console.log(data.user.name.toUpperCase()); // No null checks needed

996

console.log(data.user.profile.avatar.length); // Safe to access

997

data.tags.forEach(tag => console.log(tag.trim())); // No null in array

998

}

999

```