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
- 1 TypeScript Reference
- 2 Utility Types
- 3 TypeScript Reference: Basics
- 4 TypeScript Reference: Data Types
- 5 TypeScript Reference: Functions
- 6 TypeScript Reference: Interfaces
- 7 TypeScript Reference: Classes
- 8 TypeScript Reference: Modules
- 9 TypeScript Reference: Generics
- 10 TypeScript Reference: Decorators
- 11 TypeScript Reference: Advanced Types
- 12 FAQ:
- 12.0.1 What are utility types in TypeScript?
- 12.0.2 How do utility types help in TypeScript?
- 12.0.3 What is the Partial type in TypeScript?
- 12.0.4 Can utility types be customized or extended in TypeScript?
- 12.0.5 What is the keyof utility type in TypeScript?
- 12.0.6 How do utility types help with type checking in TypeScript?
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:
- TypeScript Handbook: A comprehensive guide to TypeScript features and syntax.
- TypeScript Playground: An interactive online editor for experimenting with TypeScript code.
- TypeScript GitHub repository: The official repository for the TypeScript source code.
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 valuesstring
: for textual valuesboolean
: for boolean values (true
orfalse
)any
: for dynamic or unknown typesvoid
: for functions that do not return a valuenull
andundefined
: 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
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 string
s, 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
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.