TypeScript is a popular programming language that provides optional static typing to JavaScript. It offers many advanced features for developers to make their code more maintainable and scalable. One of these features is advanced TypeScript types. In this tutorial, we will explore some of the most powerful and useful advanced TypeScript types.


What are Advanced TypeScript Types?

Advanced TypeScript types are a set of features that allow developers to express more complex types in their code. These types can be used to define constraints, transform data, and make more precise assertions about the types of values that are being used.


Advanced TypeScript Types in Practice

Conditional Types

Conditional types are a way of defining types that depend on other types. They allow developers to express complex type relationships based on conditions.

type TypeName<T> =
  T extends string ? "string" :
  T extends number ? "number" :
  T extends boolean ? "boolean" :
  T extends undefined ? "undefined" :
  T extends Function ? "function" :
  "object";

In this example, we define a type TypeName that takes a type parameter T. We then use the conditional type syntax to define a set of conditions based on the type of T. If T extends string, we return the string "string". If it extends number, we return "number", and so on. If none of the conditions match, we return "object".


Mapped Types

Mapped types allow developers to transform one type into another by applying a transformation function to each of its properties.

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

In this example, we define a type Readonly that takes a type parameter T. We then use the mapped type syntax to define a new type that has all the same properties as T, but with each property marked as readonly.


Template Literal Types

Template literal types allow developers to create new types by concatenating string literals with placeholders.

type CSSColor = "red" | "green" | "blue";

type BoxShadow<C extends CSSColor> = `${C} 2px 2px 2px`;

const boxShadow: BoxShadow<"red"> = "red 2px 2px 2px";

In this example, we define a type CSSColor that can only take on one of three values: "red", "green", or "blue". We then define a type BoxShadow that takes a type parameter C that extends CSSColor. We use template literal syntax to create a new string that combines the value of C with some fixed text to create a CSS box-shadow property.


Type Guards

Type guards are a way of checking the type of a value at runtime in order to narrow down its type.

function isString(value: unknown): value is string {
  return typeof value === "string";
}

function isNumber(value: unknown): value is number {
  return typeof value === "number";
}

function isStringOrNumber(value: unknown): value is string | number {
  return isString(value) || isNumber(value);
}

In this example, we define three functions that check the type of a value at runtime. The functions return a boolean value, but they also include a type assertion that narrows down the type of the value to string, number, or string | number, respectively.


Type Aliases

Type aliases allow developers to define a name for a complex type, making it easier to use and understand.

type User = {
  id: string;
  name: string
}

In this example, we define a type User that has two properties: id, which is a string, and name, which is also a string. We can then use the User type as a shortcut to refer to this complex type throughout our code.


Conclusion

Advanced TypeScript types are a powerful feature that can help developers write more maintainable and scalable code. In this tutorial, we explored some of the most useful advanced TypeScript types, including conditional types, mapped types, template literal types, type guards, and type aliases. By using these types effectively, developers can write code that is more expressive, precise, and easy to understand.