Menu
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS DSA TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI R GO KOTLIN SASS VUE GEN AI SCIPY CYBERSECURITY DATA SCIENCE INTRO TO PROGRAMMING BASH RUST

TypeScript Advanced Types


Advanced TypeScript Types

TypeScript's advanced type system allows you to model complex type relationships with precision.

These features are particularly useful for building robust, maintainable applications with excellent type safety.

Key Advanced Type Features

  • Mapped Types: Transform properties of existing types
  • Conditional Types: Create types based on conditions
  • Template Literal Types: Build types using string templates
  • Utility Types: Built-in type helpers for common transformations
  • Recursive Types: Self-referential types for tree-like structures
  • Type Guards & Type Predicates: Runtime type checking
  • Type Inference: Advanced pattern matching with infer

Mapped Types

Mapped types allow you to create new types by transforming properties of existing types.

Basic Mapped Type

Transform every property of an object type into a new type using a single template.

// Convert all properties to boolean
type Flags<T> = {
  [K in keyof T]: boolean;
};

interface User {
  id: number;
  name: string;
  email: string;
}

type UserFlags = Flags<User>;
// Equivalent to:
// {
//   id: boolean;
//   name: boolean;
//   email: boolean;
// }
Try it Yourself »

Mapped Type Modifiers

Add or remove property modifiers like readonly and ? across all keys.

// Make all properties optional
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type OptionalTodo = {
  [K in keyof Todo]?: Todo[K];
};

// Remove 'readonly' and '?' modifiers
type Concrete<T> = {
  -readonly [K in keyof T]-?: T[K];
};

// Add 'readonly' and 'required' to all properties
type ReadonlyRequired<T> = {
  +readonly [K in keyof T]-?: T[K];
};
Try it Yourself »

Key Remapping

Rename or filter keys while mapping using as, string helpers, and conditional checks.

// Add prefix to all property names
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// {
//   getId: () => number;
//   getName: () => string;
//   getEmail: () => string;
// }

// Filter out properties
type MethodsOnly<T> = {
  [K in keyof T as T[K] extends Function ? K : never]: T[K];
};
Try it Yourself »


Conditional Types

Conditional types allow you to define types that depend on a condition.

Basic Conditional Types

Select between types based on a condition checked at the type level.

type IsString<T> = T extends string ? true : false;

type A = IsString<string>;    // true
type B = IsString<number>;    // false
type C = IsString<'hello'>;    // true
type D = IsString<string | number>; // boolean

// Extract array element type
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Numbers = ArrayElement<number[]>; // number
Try it Yourself »

Infer Keyword

Capture a part of a type within a conditional type by introducing a new type variable with infer.

// Get return type of a function
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

// Get parameter types as a tuple
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

// Get constructor parameter types
type ConstructorParameters<T extends new (...args: any) => any> =
  T extends new (...args: infer P) => any ? P : never;

// Get instance type from a constructor
type InstanceType<T extends new (...args: any) => any> =
  T extends new (...args: any) => infer R ? R : any;
Try it Yourself »

Distributed Conditional Types

Understand how conditionals distribute over unions versus when they are wrapped to prevent distribution.

// Without distribution
type ToArrayNonDist<T> = T extends any ? T[] : never;
type StrOrNumArr = ToArrayNonDist<string | number>; // (string | number)[]

// With distribution
type ToArray<T> = [T] extends [any] ? T[] : never;
type StrOrNumArr2 = ToArray<string | number>; // string[] | number[]

// Filter out non-string types
type FilterStrings<T> = T extends string ? T : never;
type Letters = FilterStrings<'a' | 'b' | 1 | 2 | 'c'>; // 'a' | 'b' | 'c'
Try it Yourself »

Template Literal Types

Template literal types allow you to build types using template literal syntax.

Basic Template Literal Types

Constrain strings to specific patterns using template literals and unions.

type Greeting = `Hello, ${string}`;

const validGreeting: Greeting = 'Hello, World!';
const invalidGreeting: Greeting = 'Hi there!'; // Error

// With unions
type Color = 'red' | 'green' | 'blue';
type Size = 'small' | 'medium' | 'large';

type Style = `${Color}-${Size}`;
// 'red-small' | 'red-medium' | 'red-large' |
// 'green-small' | 'green-medium' | 'green-large' |
// 'blue-small' | 'blue-medium' | 'blue-large'
Try it Yourself »

String Manipulation Types

Apply built-in helpers to transform string literal types (uppercasing, capitalizing, etc.).

// Built-in string manipulation types
type T1 = Uppercase<'hello'>;  // 'HELLO'
type T2 = Lowercase<'WORLD'>;  // 'world'
type T3 = Capitalize<'typescript'>;  // 'Typescript'
type T4 = Uncapitalize<'TypeScript'>;  // 'typeScript'

// Create an event handler type
type EventType = 'click' | 'change' | 'keydown';
type EventHandler = `on${Capitalize<EventType>}`;
// 'onClick' | 'onChange' | 'onKeydown'
Try it Yourself »

Advanced Patterns

Compose templates with inference and key remapping to extract metadata and generate APIs.

// Extract route parameters
type ExtractRouteParams<T> =
  T extends `${string}:${infer Param}/${infer Rest}`
    ? { [K in Param | keyof ExtractRouteParams<`${Rest}`>]: string }
    : T extends `${string}:${infer Param}`
    ? { [K in Param]: string }
    : {};

type Params = ExtractRouteParams<'/users/:userId/posts/:postId'>;
// { userId: string; postId: string; }

// Create a type-safe event emitter
type EventMap = {
  click: { x: number; y: number };
  change: string;
  keydown: { key: string; code: number };
};

type EventHandlers = {
  [K in keyof EventMap as `on${Capitalize<K>}`]: (event: EventMap[K]) => void;
};
Try it Yourself »

Utility Types

TypeScript provides several built-in utility types for common type transformations.

Common Utility Types

Use built-ins like Partial, Pick, and Omit for common transformations.

// Basic types
interface User {
  id: number;
  name: string;
  email: string;
  createdAt: Date;
}

// Make all properties optional
type PartialUser = Partial<User>;

// make all properties required
type RequiredUser = Required<PartialUser>;

// make all properties read-only
type ReadonlyUser = Readonly<User>;

// pick specific properties
type UserPreview = Pick<User, 'id' | 'name'>;

// omit specific properties
type UserWithoutEmail = Omit<User, 'email'>;

// extract property types
type UserId = User['id']; // number
type UserKeys = keyof User; // 'id' | 'name' | 'email' | 'createdAt'
Try it Yourself »

Advanced Utility Types

Exclude or extract members from unions and create custom mapped helpers.

// Create a type that excludes null and undefined
type NonNullable<T> = T extends null | undefined ? never : T;

// Exclude types from a union
type Numbers = 1 | 2 | 3 | 'a' | 'b';
type JustNumbers = Exclude<Numbers, string>; // 1 | 2 | 3

// Extract types from a union
type JustStrings = Extract<Numbers, string>; // 'a' | 'b'

// Get the type that is not in the second type
type A = { a: string; b: number; c: boolean };
type B = { a: string; b: number };
type C = Omit<A, keyof B>; // { c: boolean }

// Create a type with all properties as mutable
type Mutable<T> = {
  -readonly [K in keyof T]: T[K];
};
Try it Yourself »

Recursive Types

Recursive types are useful for modeling tree-like data structures where a type can reference itself.

Basic Recursive Type

Model self-referential structures like trees and nested JSON.

// Simple binary tree
type BinaryTree<T> = {
  value: T;
  left?: BinaryTree<T>;
  right?: BinaryTree<T>;
};

// JSON-like data structure
type JSONValue =
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue };

// Nested comments
type Comment = {
  id: number;
  content: string;
  replies: Comment[];
  createdAt: Date;
};
Try it Yourself »

Advanced Recursive Types

Express linked lists, directory trees, and recursive state machines.

// Type for a linked list
type LinkedList<T> = {
  value: T;
  next: LinkedList<T> | null;
};

// Type for a directory structure
type File = {
  type: 'file';
  name: string;
  size: number;
};

type Directory = {
  type: 'directory';
  name: string;
  children: (File | Directory)[];
};

// Type for a state machine
type State = {
  value: string;
  transitions: {
    [event: string]: State;
  };
};

// Type for a recursive function
type RecursiveFunction<T> = (x: T | RecursiveFunction<T>) => void;
Try it Yourself »

Best Practices

When to Use Advanced Types

  • Use mapped types when you need to transform multiple properties of an object type
  • Use conditional types when your type depends on another type
  • Use template literal types for string manipulation and pattern matching
  • Use utility types for common transformations (prefer built-in ones when possible)
  • Use recursive types for tree-like or nested data structures

Performance Considerations

  • Deeply nested recursive types can slow down the TypeScript compiler
  • Very large union types (100+ members) can cause performance issues
  • Use type aliases to break down complex types

Common Pitfalls

Type Inference Issues

  • Conditional types distribute over union types, which can be surprising
  • Type inference with infer works differently in different contexts
  • Some utility types don't work well with any or unknown

Maintainability

  • Overusing complex types can make code hard to understand
  • Document complex type transformations with comments
  • Consider using type assertions or helper functions for very complex types


×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
[email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
[email protected]

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2025 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.