█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Programming Languages/TypeScript/Advanced Types
55 minAdvanced

Advanced Types

After this lesson, you will be able to: Apply mapped types, conditional types, template literal types, infer, and the utility types.

Advanced TS. Used by library authors; senior application devs should recognise + occasionally write.

Prerequisites:Generics

Utility types you'll use weekly

Built-in. Memorise these.

tsx
type User = { id: string; name: string; email: string; admin: boolean };
type PartialUser = Partial<User>; // all fields optional
type RequiredUser = Required<User>; // all fields required
type ReadonlyUser = Readonly<User>;
type Pub = Omit<User, "admin">;
type Min = Pick<User, "id" | "name">;
type Map = Record<"admin" | "member", User>;
type UserKeys = keyof User;
type IdType = User["id"];
// Function-related
function fetch(id: string, opts?: { cache: boolean }): Promise<User> { return null as any; }
type Args = Parameters<typeof fetch>; // [string, opts?: ...]
type Ret = ReturnType<typeof fetch>; // Promise<User>
type Resolved = Awaited<Ret>; // User
// String types
type NonEmpty<T extends string> = T extends "" ? never : T;
type Upper = Uppercase<"hello">; // "HELLO"

Mapped types

Transform keys of an object type.

tsx
type Nullable<T> = { [K in keyof T]: T[K] | null };
type NullableUser = Nullable<User>;
// Pick from another type
type Keys<T> = { [K in keyof T]-?: K }[keyof T]; // -? makes required
// Add prefix to keys (template literal magic)
type Prefixed<T, P extends string> = {
[K in keyof T as `${P}${string & K}`]: T[K];
};
type DBUser = Prefixed<User, "db_">;
// { db_id: string; db_name: string; db_email: string; db_admin: boolean }

Conditional types + infer

Type-level if/else.

html
type IsArray<T> = T extends any[] ? true : false;
type A = IsArray<number[]>; // true
type B = IsArray<number>; // false
// Extract type from a generic
type ElementOf<T> = T extends (infer U)[] ? U : never;
type N = ElementOf<number[]>; // number
// Extract the promise's resolved type
type Unwrap<T> = T extends Promise<infer U> ? U : T;
type X = Unwrap<Promise<string>>; // string
type Y = Unwrap<number>; // number
// Template literal type
type Event = `on${"Click" | "Hover" | "Focus"}`;
// "onClick" | "onHover" | "onFocus"

Common mistakes only experienced TS devs avoid

Reaching for advanced types when simple ones work. Over-engineering hurts readability. Recursive mapped types that hit the depth limit. Linear is fine; trees rarely. Forgetting `as const` on tuples. Without it, TS widens to plain arrays. Casting with `as Type` instead of fixing the underlying type.

Quick Check

What does `type Element<T> = T extends (infer U)[] ? U : never` do?

Pick the cleanest answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Generics
Back to TypeScript
TypeScript with React→