TypeScript Reference : Utility Types

TypeScript Reference : Utility Types

When working with TypeScript, understanding and utilizing the power of utility types is important. Utility types are helpful predefined types that exist within the TypeScript standard library and can be used to manipulate and transform existing types. These utility types provide convenient and expressive functionality, allowing developers to quickly and easily work with complex types and perform common operations.

A utility type that is commonly used is the Partial type. The Partial type allows us to make all the properties of a given type optional, by creating a new type with the same properties, but with each property marked as optional using the ? syntax. This can be useful when we want to create an object that matches a specific type, but not all of the properties are required.

Another useful utility type is the Pick type. This type allows us to create a new type by selecting a subset of properties from an existing type. We can provide a list of properties we want to include in the new type, and TypeScript will create a new type that only includes those properties. This can be helpful when we want to work with a smaller subset of properties from a larger type.

The Record utility type is also commonly used. This type allows us to create a new type with specified keys and values. We can provide a list of keys and a type for the values, and TypeScript will create a new type based on these specifications. This can be useful for creating lookup tables or dictionaries, where we want to associate a specific key with a specific value.

In summary, utility types in TypeScript provide powerful tools for working with complex types and performing common operations. The Partial, Pick, and Record utility types are just a few examples of the many utility types available in TypeScript. By understanding and utilizing these utility types, developers can write more expressive and type-safe code.

Table of Contents

TypeScript Reference

Overview

TypeScript is a statically typed superset of JavaScript that compiles to plain JavaScript. It adds optional static typing, classes, interfaces, and modules to JavaScript, enabling developers to build large-scale JavaScript applications more easily.

Documentation

The TypeScript documentation provides a comprehensive reference for the TypeScript language. It covers everything from basic types and syntax to advanced topics such as decorators and declaration merging.

Utility Types

TypeScript comes with a set of utility types that provide additional functionality and convenience when working with types. These utility types are generic types that can be used with other types to modify or transform them.

  • Partial<T>: Constructs a type with all properties of T set to optional.
  • Required<T>: Constructs a type with all properties of T set to required.
  • Readonly<T>: Constructs a type with all properties of T set to readonly.
  • Record<K, T>: Constructs an object type whose property keys are K and values are T.
  • Pick<T, K>: Constructs a type by picking the set of properties K from T.

Resources

In addition to the official TypeScript documentation, there are several other resources available for learning TypeScript:

Conclusion

TypeScript is a powerful language that brings static typing and advanced features to JavaScript. The TypeScript documentation and utility types provide a wealth of information and tools to help developers write better and more maintainable code.

Utility Types

Utility types are generic types that can be used to transform and manipulate other types in TypeScript. These utility types provide a convenient way to perform common operations on types, such as extracting properties, mapping one type to another, or transforming a type based on specific conditions.

Partial

The Partial utility type allows you to create a new type that has all properties of the original type, but with each property marked as optional.

For example, if you have a type Person with properties name and age, you can use Partial<Person> to create a new type where both name and age properties are optional.

type Person = {

name: string;

age: number;

};

type PartialPerson = Partial<Person>;

// PartialPerson is equivalent to:

// {

// name?: string | undefined;

// age?: number | undefined;

// }

Required

The Required utility type does the opposite of Partial. It creates a new type that has all properties of the original type, but with each property marked as required.

Using the same example, you can use Required<Person> to create a new type where both name and age properties are required.

type Person = {

name?: string | undefined;

age?: number | undefined;

};

type RequiredPerson = Required<Person>;

// RequiredPerson is equivalent to:

// {

// name: string;

// age: number;

// }

Pick

The Pick utility type allows you to create a new type by picking only specific properties from an existing type.

For example, if you have a type Person with properties name, age, and gender, you can use Pick<Person, 'name' | 'gender'> to create a new type that only includes the name and gender properties.

type Person = {

name: string;

age: number;

gender: string;

};

type NameAndGender = Pick<Person, 'name' | 'gender'>;

// NameAndGender is equivalent to:

// {

// name: string;

// gender: string;

// }

Omit

The Omit utility type is similar to Pick, but it creates a new type by omitting specific properties from an existing type.

Using the same example, you can use Omit<Person, 'age'> to create a new type that includes all properties of Person, except the age property.

type Person = {

name: string;

age: number;

gender: string;

};

type PersonWithoutAge = Omit<Person, 'age'>;

// PersonWithoutAge is equivalent to:

// {

// name: string;

// gender: string;

// }

Record

The Record utility type allows you to create a new type by specifying the keys and values of an object type.

For example, you can use Record<string, number> to create a new type where the keys are strings and the values are numbers.

type NumberRecord = Record<string, number>;

// NumberRecord is equivalent to:

// {

// [key: string]: number;

// }

Conclusion

These are just a few examples of the utility types provided by TypeScript. There are many other utility types available, such as Readonly, Exclude, and Extract, that offer powerful ways to manipulate and transform types in your TypeScript code.

By using utility types, you can write more expressive and reusable code, reduce potential errors, and leverage the full potential of TypeScript’s type system.

TypeScript Reference: Basics

What is TypeScript?

TypeScript is an open-source programming language developed and maintained by Microsoft. It is a superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code. TypeScript adds optional static typing to JavaScript, providing developers with features for better tooling, scalability, and maintainability.

TypeScript Syntax

The syntax of TypeScript is similar to JavaScript, but with added type annotations and static typing. These features allow the compiler to catch potential errors during development and provide helpful hints and autocompletion to developers.

Declaring Variables

In TypeScript, variables can be declared using the let or const keywords, similar to JavaScript. However, TypeScript also allows the use of type annotations to explicitly specify the type of a variable:

let name: string = "John";

const age: number = 25;

Basic Types

TypeScript provides several built-in basic types, including:

  • number: for numeric values
  • string: for textual values
  • boolean: for boolean values (true or false)
  • any: for dynamic or unknown types
  • void: for functions that do not return a value
  • null and undefined: for representing absence of value

Functions

Functions in TypeScript can have type annotations for parameters and return values, which enable better static type checking. For example:

function addNumbers(a: number, b: number): number {

return a + b;

}

Interfaces

TypeScript supports interfaces, which define the structure of objects. Interfaces can be used to enforce that an object must have certain properties and methods. For example:

interface Person {

name: string;

age: number;

}

function introduce(person: Person): void {

console.log(`My name is ${person.name} and I am ${person.age} years old.`);

}

Classes

Classes in TypeScript allow developers to define blueprint for creating objects with properties and methods. TypeScript supports class inheritance and access modifiers like public, private, and protected. For example:

class Animal {

protected name: string;

constructor(name: string) {

this.name = name;

}

move(distance: number): void {

console.log(`${this.name} moved ${distance} meters.`);

}

}

Modules

TypeScript has built-in support for modules, allowing developers to organize their code into reusable and maintainable units. Modules can be imported and exported using the import and export keywords. For example:

// math.ts

export function addNumbers(a: number, b: number): number {

return a + b;

}

export function subtractNumbers(a: number, b: number): number {

return a - b;

}

// app.ts

import { addNumbers, subtractNumbers } from './math';

console.log(addNumbers(5, 3)); // Output: 8

console.log(subtractNumbers(10, 4)); // Output: 6

Generics

Generics allow developers to define functions and classes that can work with multiple types. This enables the creation of reusable and type-safe code. For example:

function reverse(items: T[]): T[] {

return items.reverse();

}

const numbers: number[] = [1, 2, 3, 4, 5];

const reversedNumbers: number[] = reverse(numbers);

const names: string[] = ["John", "Jane", "Joe"];

const reversedNames: string[] = reverse(names);

Conclusion

This is just a brief overview of the basics of TypeScript. TypeScript offers many more features and capabilities that can greatly enhance the development experience and productivity of JavaScript developers. It is widely used in modern web development and is supported by major IDEs and frameworks.

TypeScript Reference: Data Types

Introduction

Introduction

In TypeScript, data types are used to specify the type of values that can be assigned to variables, function parameters, and function return types. By explicitly declaring data types, TypeScript enables static type checking, which helps catch errors during development and provides better tooling support.

Primitive Data Types

There are several built-in primitive data types in TypeScript:

  • number: Represents numerical values. TypeScript supports both integer and floating-point numbers.
  • string: Represents textual data. Strings are enclosed in single quotes (‘) or double quotes (“).
  • boolean: Represents a logical value – either true or false.
  • null: Represents the absence of a value. It is a special value that signifies the intentional absence of any object value.
  • undefined: Represents a variable that has been declared but has not been assigned a value.
  • symbol: Represents a unique identifier. Symbols are often used as keys in objects to avoid naming collisions.

Object Types

In addition to the primitive data types, TypeScript also supports object types:

  • object: Represents a generic object. It can hold properties and methods.
  • array: Represents a collection of values that are sequentially ordered. Arrays can contain elements of any data type.
  • tuple: Represents an array with a fixed number of elements, each with a known type. The type of each element in the tuple is specified in the declaration.
  • enum: Represents a set of named constants. Enums can be used to define a collection of related values.

Other Data Types

There are a few other data types in TypeScript that provide more granular control over the allowed values:

  • any: Represents values of any type. Variables of type “any” can be assigned values of any type, and any operation can be performed on them without type checking.
  • unknown: Represents values of an unknown type. Unlike “any”, variables of type “unknown” cannot be assigned to variables of other types without proper type checking or assertion.
  • never: Represents the type of values that never occur. It is used to indicate functions that never return or variables that cannot have a value.
  • void: Represents the absence of any type. It is used as the return type of functions that do not return a value.

Type Inference

TypeScript has a feature called “type inference” that automatically infers the type of a variable based on its value. This allows you to omit the explicit type annotation if TypeScript can determine the type from the assigned value. However, it is generally recommended to explicitly declare the data types for better code readability and maintainability.

Conclusion

Understanding the different data types in TypeScript is essential for writing type-safe and maintainable code. By using the appropriate data types, you can reduce the risk of runtime errors and improve the overall quality of your TypeScript projects.

TypeScript Reference: Functions

Introduction to Functions in TypeScript

A function is a block of code that performs a specific task. In TypeScript, functions play a crucial role in writing reusable and modular code. This section will explain the different aspects of defining and using functions in TypeScript.

Function Declaration

In TypeScript, functions can be declared using the traditional function declaration syntax:

function add(a: number, b: number): number {

return a + b;

}

The above code declares a function named add that takes two parameters of type number and returns a value of type number. The a and b parameters are optional, meaning that they can be passed to the function or not.

Function Expression

In addition to function declarations, TypeScript also supports function expressions, where a function is assigned to a variable:

const add = function(a: number, b: number): number {

return a + b;

};

Function expressions can be useful when you need to assign a function to a variable or pass it as an argument to another function.

Arrow Functions

An arrow function is a more concise way of writing a function expression. It uses the => syntax:

const add = (a: number, b: number): number => {

return a + b;

};

Arrow functions are often used with arrays and objects to perform tasks like mapping, filtering, and reducing.

Type Annotations

In TypeScript, you can specify the types of function parameters and the return type using type annotations:

function add(a: number, b: number): number {

return a + b;

}

The above code specifies that the a and b parameters should be of type number, and the return value should also be of type number.

Optional Parameters

By default, function parameters in TypeScript are required, meaning that they must be provided when invoking the function. However, you can make a parameter optional by appending a ? to its name:

function greet(name?: string): string {

if (name) {

return "Hello, " + name + "!";

}

return "Hello, guest!";

}

In the above example, the name parameter is optional. If a value is provided, the function will return a personalized greeting. If no value is provided, it will return a generic greeting.

Default Values

In TypeScript, you can assign default values to function parameters:

function greet(name: string = "guest"): string {

return "Hello, " + name + "!";

}

If no value is provided for the name parameter, it will default to "guest". Otherwise, the provided value will be used when constructing the greeting.

Rest Parameters

Rest parameters allow you to pass an arbitrary number of arguments to a function. They are denoted by three dots (…) followed by the parameter name:

function sum(...numbers: number[]): number {

return numbers.reduce((acc, val) => acc + val, 0);

}

The sum function accepts any number of arguments and returns their sum. The arguments are collected into an array called numbers, which allows you to perform operations on them using array methods like reduce.

Function Overloading

Function overloading is a feature in TypeScript that allows a function to have multiple signatures. Each signature specifies the types of parameters and return values for a particular set of arguments:

function greet(name: string): string;

function greet(names: string[]): string;

function greet(names: string | string[]): string {

if (Array.isArray(names)) {

return "Hello, " + names.join(" and ") + "!";

}

return "Hello, " + names + "!";

}

In the above example, the greet function has three signatures. The first signature accepts a single string parameter, the second signature accepts an array of strings, and the third signature is the actual implementation of the function.

Conclusion

Functions are an essential part of TypeScript and are used to encapsulate reusable blocks of code. Understanding function declaration, expression, arrow functions, type annotations, optional parameters, default values, rest parameters, and function overloading will help you write more efficient and maintainable code in TypeScript.

TypeScript Reference: Interfaces

Introduction

An interface in TypeScript defines a contract for objects that implement it. It describes the structure, properties, and methods that a class or object must have in order to be considered compatible with the interface.

Syntax

To define an interface in TypeScript, use the interface keyword followed by the name of the interface:

interface MyInterface {

// properties and methods

}

Properties

Interface properties define the structure of the objects that implement the interface. They can have different types such as number, string, boolean, or custom types:

interface Person {

name: string;

age: number;

readonly id: string;

}

In the example above, the Person interface has three properties: name and age of type string and number respectively, and id of type string. The id property is marked as readonly, which means it cannot be modified once it is assigned a value.

Methods

Interface methods define the behavior of the objects that implement the interface. They can have different parameters and return types:

interface Calculator {

add(a: number, b: number): number;

subtract(a: number, b: number): number;

}

The Calculator interface defines two methods: add and subtract. Each method takes two parameters of type number and returns a number.

Implementing an Interface

To implement an interface in TypeScript, a class or object must provide the structure, properties, and methods defined by the interface. This is done using the implements keyword:

class Circle implements Shape {

radius: number;

constructor(radius: number) {

this.radius = radius;

}

getArea() {

return Math.PI * this.radius * this.radius;

}

}

In the example above, the Circle class implements the Shape interface, which requires the implementation of the radius property and the getArea method. The class provides these properties and methods, making it compatible with the Shape interface.

Extending Interfaces

Interfaces can also extend other interfaces, allowing for the combination of multiple interfaces into a single interface:

interface Animal {

name: string;

sound(): void;

}

interface Cat extends Animal {

sleep(): void;

}

In the example above, the Cat interface extends the Animal interface, inheriting its properties and methods. The Cat interface adds an additional method called sleep. This allows a class or object that implements the Cat interface to have both the name, sound, and sleep properties and methods.

Conclusion

Interfaces in TypeScript provide a way to define the structure and behavior of objects. They can be used to create reusable components, enforce a contract between different parts of an application, and enable better collaboration between developers working on a project.

TypeScript Reference: Classes

Introduction

In TypeScript, a class is a blueprint for creating objects with specific properties and methods. It is a reusable template that defines the structure and behavior of objects of the same type.

Defining a Class

Defining a Class

To define a class in TypeScript, use the class keyword followed by the class name. Here’s an example:

class Person {

name: string;

constructor(name: string) {

this.name = name;

}

sayHello() {

console.log('Hello, ' + this.name);

}

}

In the above example, we defined a class called “Person” with a property name, a constructor that takes a name as a parameter, and a method sayHello(). The constructor is a special method that gets called when an object is created from the class.

Creating Objects from a Class

To create an object from a class, use the new keyword followed by the class name and any required parameters for the constructor. Here’s an example:

const person = new Person('John');

person.sayHello(); // Output: Hello, John

In the above example, we created an object of type Person with the name “John” and called the sayHello() method on it.

Inheritance

In TypeScript, classes can inherit properties and methods from other classes using the extends keyword. This is known as inheritance. Here’s an example:

class Employee extends Person {

department: string;

constructor(name: string, department: string) {

super(name);

this.department = department;

}

getDepartment() {

return this.department;

}

}

In the above example, we defined a class called “Employee” that inherits from the base class “Person”. It adds a new property department and a method getDepartment(). The super keyword is used to call the constructor of the base class.

Summary

Classes in TypeScript provide a way to define reusable templates for creating objects with specific properties and methods. They support inheritance, allowing new classes to extend and inherit functionality from existing classes.

TypeScript Reference: Modules

Introduction

In TypeScript, modules provide a way to organize and encapsulate code. They allow you to split your codebase into smaller parts, which can then be imported and used in other parts of your application. Modules help to keep your codebase clean, maintainable, and reusable.

Exporting and Importing

To use a module, you need to export its functions, classes, or variables so that they can be accessed from other modules. This can be done using the export keyword.

// module.ts

export function add(a: number, b: number): number {

return a + b;

}

To import a module, you can use the import keyword followed by the module name and the desired exported member.

// main.ts

import { add } from './module';

console.log(add(2, 3)); // Output: 5

Default Exports

Modules can also have a default export, which is the main exported item from the module. This is useful when you want to export a single value or function as the main entry point of the module.

// module.ts

export default function greet(name: string): void {

console.log(`Hello, ${name}!`);

}

When importing a module with a default export, you can choose any name for the imported member.

// main.ts

import sayHello from './module';

sayHello('John'); // Output: Hello, John!

Namespace Imports

TypeScript also supports namespace imports, which allow you to import all the exported members from a module under a single namespace.

// module.ts

export const PI = 3.14159;

export function multiply(a: number, b: number): number {

return a * b;

}

// main.ts

import * as math from './module';

console.log(math.PI); // Output: 3.14159

console.log(math.multiply(2, 3)); // Output: 6

Conclusion

Modules are an essential part of organizing and structuring code in TypeScript. They provide a way to split up your codebase into smaller parts that can be imported and used throughout your application. Understanding how to export and import modules is crucial for creating reusable and maintainable TypeScript code.

TypeScript Reference: Generics

In TypeScript, generics allow us to create functions, classes, and interfaces that can work with a variety of types without sacrificing type safety.

Using Generics with Functions

When defining a function with generics, we can specify one or more type parameters enclosed in angle brackets (<>). These type parameters can then be used as placeholders for the actual types that will be passed as arguments.

Here’s an example:

function identity<T>(arg: T): T {

return arg;

}

let result = identity("hello");

console.log(result); // output: "hello"

let anotherResult = identity(123);

console.log(anotherResult); // output: 123

In the example above, the T type parameter is used to specify the type of the argument and the return value. The type of the argument arg is inferred based on the type of the value passed when calling the function.

Using Generics with Classes

Generics can also be used with classes to create reusable components that can work with different types.

Here’s an example:

class Box<T> {

private item: T;

constructor(item: T) {

this.item = item;

}

getItem(): T {

return this.item;

}

}

let boxOfString = new Box("Apple");

console.log(boxOfString.getItem()); // output: "Apple"

let boxOfNumber = new Box(123);

console.log(boxOfNumber.getItem()); // output: 123

In the example above, the T type parameter is used to specify the type of the item stored in the box. The type of the item is inferred based on the value passed when creating an instance of the class.

Using Generics with Interfaces

Generics can also be used with interfaces to define reusable types that can work with multiple types.

Here’s an example:

interface Pair<T, U> {

first: T;

second: U;

}

let pairOfStringAndNumber: Pair<string, number> = {

first: "hello",

second: 123

};

console.log(pairOfStringAndNumber.first); // output: "hello"

console.log(pairOfStringAndNumber.second); // output: 123

In the example above, the T and U type parameters are used to specify the types of the first and second properties of the Pair interface. When declaring a variable of type Pair<string, number>, the type of the first property is inferred as string and the type of the second property is inferred as number.

Generics provide a powerful way to create reusable and type-safe code by allowing us to abstract over different types. By using generics, we can write more generic and flexible functions, classes, and interfaces that can be used with multiple types, while still ensuring type safety.

TypeScript Reference: Decorators

Introduction

Decorators are a feature in TypeScript that allow you to add metadata to classes, methods, properties, and parameters at design time. They provide a way to modify or enhance the behavior of the target they are applied to. Decorators are declared using the `@` symbol followed by the decorator name, which can be a function or a class.

Usage

To use decorators in TypeScript, you need to enable the `experimentalDecorators` compiler option in your `tsconfig.json` file. This can be done by setting the value of `experimentalDecorators` to `true` in the `compilerOptions` section:

“`json

{

“compilerOptions”: {

“experimentalDecorators”: true

}

}

“`

Once you have enabled decorators, you can apply them to different entities in your code. Here are some examples of how decorators can be used:

  • Class Decorators: Decorators can be applied to classes to modify their behavior. They can be used to add additional functionality, log information, or restrict access to certain methods or properties.

  • Method Decorators: Decorators can be applied to individual methods within a class. They can be used to instrument methods, validate inputs, or control the execution flow.

  • Property Decorators: Decorators can be applied to properties of a class. They can be used to validate or format data, enforce business rules, or implement lazy initialization.

  • Parameter Decorators: Decorators can be applied to parameters of a method or constructor. They can be used to validate inputs, provide default values, or inject dependencies.

Creating Custom Decorators

You can also create your own decorators by defining a function or class that implements the desired behavior. This allows you to create reusable decorators and apply them to multiple entities in your codebase. Here is an example of a custom decorator that logs the execution time of a method:

“`typescript

function executionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {

const originalMethod = descriptor.value;

descriptor.value = function(…args: any[]) {

const startTime = performance.now();

const result = originalMethod.apply(this, args);

const endTime = performance.now();

console.log(`Method ${propertyKey} took ${endTime – startTime}ms to execute.`);

return result;

}

return descriptor;

}

class ExampleClass {

@executionTime

expensiveMethod() {

// Some expensive operation

}

}

“`

In this example, the `executionTime` decorator is applied to the `expensiveMethod` of the `ExampleClass`. When the method is called, the decorator logs the execution time to the console.

Conclusion

Decorators are a powerful feature in TypeScript that allow you to easily add metadata and modify the behavior of classes, methods, properties, and parameters. They enable you to write cleaner and more maintainable code by separating cross-cutting concerns from the core logic. With the ability to create custom decorators, you can extend the functionality of your codebase in a reusable manner.

TypeScript Reference: Advanced Types

Type Guards

Type Guards in TypeScript allow you to narrow down the type of an object based on a condition. They are especially useful when working with union types or more complex types.

The most common type guard in TypeScript is the typeof type guard. It allows you to narrow down the type of a variable based on its value using the typeof operator.

function printLength(strOrNum: string | number) {

if (typeof strOrNum === "string") {

console.log(strOrNum.length); // OK

} else {

console.log(strOrNum.toFixed(2)); // OK

}

}

Another commonly used type guard is the instanceof type guard. It allows you to narrow down the type of an object based on its constructor function.

class Circle {

radius: number;

constructor(radius: number) {

this.radius = radius;

}

getArea() {

return Math.PI * this.radius ** 2;

}

}

class Rectangle {

width: number;

height: number;

constructor(width: number, height: number) {

this.width = width;

this.height = height;

}

getArea() {

return this.width * this.height;

}

}

function printShapeArea(shape: Circle | Rectangle) {

if (shape instanceof Circle) {

console.log(shape.getArea()); // OK

} else {

console.log(shape.getArea()); // OK

}

}

Type Aliases

Type Aliases allow you to create your own custom types in TypeScript. They are especially helpful for creating complex or reusable types.

Here’s an example of a type alias for a complex type:

type Point = {

x: number;

y: number;

};

function printPoint(point: Point) {

console.log(`(${point.x}, ${point.y})`);

}

const myPoint: Point = { x: 3, y: 5 };

printPoint(myPoint); // Output: (3, 5)

Type Assertions

Type Assertions in TypeScript allow you to tell the compiler that you know more about the type of a value than what TypeScript can infer.

Type Assertions are denoted by the as keyword. Here’s an example:

const message: unknown = "Hello, TypeScript!";

const messageLength = (message as string).length;

console.log(messageLength); // Output: 19

Mapped Types

Mapped Types provide a way to create new types based on existing types by transforming each property in the original type.

The keyof operator is used to get the keys of an object type, and the in keyword is used to iterate over each key:

type Person = {

name: string;

age: number;

};

type PersonPartial = {

[K in keyof Person]?: Person[K];

};

const partialPerson: PersonPartial = { name: "John" };

Conditional Types

Conditional Types allow you to define types that depend on other types. They are particularly useful when working with generic types.

The syntax for defining conditional types is T extends U ? X : Y. It reads as “if type T is assignable to type U, then the type is X, otherwise it is Y”.

type StringOrNumber = T extends string ? string : number;

const example1: StringOrNumber = "Hello";

const example2: StringOrNumber = 42;

Intersection Types

Intersection Types allow you to combine multiple types into a single type that has all the properties of the intersected types.

type Animal = {

name: string;

};

type Flyable = {

fly: () => void;

};

type Bird = Animal & Flyable;

const bird: Bird = {

name: "Eagle",

fly() {

console.log("Flying high");

},

};

Union Types

Union Types allow you to specify that a value can have more than one type. They are useful for representing values that can have multiple possible shapes.

type Shape = Circle | Rectangle;

function printArea(shape: Shape) {

if ("radius" in shape) {

console.log(shape.radius); // OK

} else {

console.log(shape.width * shape.height); // OK

}

}

Conclusion

Advanced types in TypeScript provide powerful features to help you write more expressive and type-safe code. Type guards, type aliases, type assertions, mapped types, conditional types, intersection types, and union types are just some of the advanced type features you can leverage to enhance your development experience with TypeScript.

FAQ:

What are utility types in TypeScript?

Utility types in TypeScript are predefined types that provide common functionality and help to manipulate and transform other types. They are built-in and available for use without any additional configuration. They are used to perform common operations on types, such as picking, omitting, mapping, and transforming types.

How do utility types help in TypeScript?

Utility types in TypeScript provide convenient ways to manipulate and transform types without having to write repetitive code. They help to avoid code duplication and make the code more readable and maintainable. By using utility types, developers can easily pick or omit properties from objects, map types, transform function types, and perform other common operations on types.

What is the Partial type in TypeScript?

The Partial type in TypeScript is a utility type that makes all properties of an object optional. It creates a new type that has the same properties as the original type, but each property is marked as optional. This allows developers to create objects with optional properties without manually marking each property as optional.

Can utility types be customized or extended in TypeScript?

No, utility types in TypeScript cannot be customized or extended. They are predefined and built-in types that provide specific functionality. However, developers can create their own custom utility types by using generics and type inference to define reusable transformations and operations on types.

What is the keyof utility type in TypeScript?

The keyof utility type in TypeScript is a built-in utility type that represents the union of all possible property names of an object type. It allows developers to extract the keys of an object type and use them to create new types or perform other operations. This is useful when working with dynamic or generic code that needs to access or manipulate the keys of an object.

How do utility types help with type checking in TypeScript?

Utility types in TypeScript help with type checking by providing predefined type transformations and operations that ensure type safety and correctness. They allow developers to easily manipulate and transform types while keeping the type system consistent and preventing common type errors. This helps to catch potential bugs and provides better IDE support and auto-completion.