TypeScript: Guide for JavaScript Devs
Introduction to TypeScript: improve your JavaScript with typing.
Published:Introduction
TypeScript is a superset of JavaScript, which means it extends JavaScript by adding static typing and other advanced features. This helps improve code quality and reduce errors. This guide will show you how to transition from JavaScript to TypeScript, exploring fundamental concepts and best practices.
// TypeScript function with specified types
function add(a: number, b: number): number {
return a + b;
}
console.log(add(5, 3)); // Output: 8
console.log(add("5", "3")); // Error: arguments must be numbers
Why use TypeScript instead of JavaScript?
TypeScript offers various advantages over pure JavaScript:
- Static Typing: Prevents common errors and makes the code more secure and maintainable.
- Improved Auto-completion: Code editors provide better suggestions thanks to type knowledge.
- Simplified Debugging: Errors are detected during compilation, reducing runtime bugs.
- Compatibility: Can be gradually adopted in existing projects, as it is compatible with JavaScript.
However, there are also some disadvantages:
- Configuration and Compilation: Requires an additional compilation process, increasing build complexity.
- Learning Curve: It may take time to learn all the new features and best practices.
- Overhead: Typing can be verbose, making the code longer and more detailed.
For medium or large-sized projects, TypeScript can save time and significantly reduce errors. If you are familiar with JavaScript, learning TypeScript will be relatively simple.
Installation of TypeScript
To start using TypeScript, install it with npm
. Make sure you have Node.js installed, then run:
npm install -g typescript
Verify the installation by checking the version with the command:
tsc --version
Compiling TypeScript
To start using TypeScript, create a file named index.ts
with the following content:
function greet(name: string): string {
return "Hello, " + name;
}
console.log(greet("World"));
To compile the index.ts
file into JavaScript, open the terminal and run:
tsc index.ts
This will generate a file named index.js
in the same directory, which can be executed with Node.js or included in a web project.
You can also use the -w
option to have TypeScript automatically compile files whenever they are saved:
tsc index.ts -w
This command will enable watch mode, monitoring the index.ts
file for changes and recompiling it automatically.
What is tsc
and Transpilation
The tsc
command stands for "TypeScript Compiler". It reads TypeScript code, checks for type correctness, and transforms (or transpiles) it into JavaScript. Transpilation is the process of converting TypeScript code into JavaScript code, which can be executed in any JavaScript environment, such as browsers or Node.js.
You can also configure the compilation process by creating a tsconfig.json
file. This file allows you to specify various options for the TypeScript compiler. To create a tsconfig.json
file with basic settings, you can run:
tsc --init
A typical tsconfig.json
file might look like this:
{
"compilerOptions": {
"target": "es6", // Version of JavaScript to compile to
"module": "commonjs", // Module system to use (e.g., CommonJS for Node.js)
"strict": true, // Enable all strict type-checking options
"esModuleInterop": true, // Enable interoperability between ES modules
"skipLibCheck": true, // Skip type checking of declaration files
"forceConsistentCasingInFileNames": true // Enforce consistent casing in file names
},
"include": ["src"] // Specify which files to include in the compilation
}
After creating the tsconfig.json
file, you can simply run the tsc
command without arguments to compile all TypeScript files in the project according to the specified settings:
tsc -w
This command will enable watch mode, monitoring all TypeScript files in the project for changes and recompiling them automatically.
Primitive Types in TypeScript
TypeScript provides several primitive types that you can use to clearly define the type of data you are working with. The main primitive types are:
string: Represents a sequence of characters.
let color: string = "blue";
let fullName: string = `John Doe`;
let age: number = 37;
let sentence: string = `Name ${fullName}. Age ${age}.`;
number: Represents a number, both integer and decimal.
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
bigint: Represents a large integer number.
let big: bigint = 100n;
boolean: Represents a boolean value (true or false).
let isDone: boolean = false;
undefined: Represents an undefined value.
let u: undefined = undefined;
null: Represents a null value.
let n: null = null;
symbol: Represents a unique and immutable value.
let sym: symbol = Symbol("unique");
Arrays in TypeScript
In TypeScript, you can declare arrays of various types. Here are some examples of how to declare and use arrays:
Array of numbers:
let list: number[] = [1, 2, 3];
Array of strings:
let colors: string[] = ["red", "green", "blue"];
Generic arrays: You can use the Array
object with generic notation.
let listGeneric: Array<number> = [1, 2, 3];
Objects in TypeScript
Objects in TypeScript are similar to those in JavaScript, but with the added ability to define types for properties. Here are some examples of declaring and using objects:
Simple object:
let person: {name: string, age: number} = {
name: "John",
age: 30
};
Object with optional types: You can declare optional properties using the question mark (?
).
let person: {name: string, age?: number} = {
name: "John"
};
Complex object: You can nest objects and arrays within other objects.
let company: {
name: string,
employees: {name: string, age: number}[],
isActive: boolean
} = {
name: "Tech Corp",
employees: [
{name: "Alice", age: 30},
{name: "Bob", age: 25}
],
isActive: true
};
Interfaces in TypeScript
Interfaces in TypeScript allow you to define the structure of objects more clearly and reusable. Here is how you can use interfaces for the previous examples of objects:
Simple object:
interface Person {
name: string;
age: number;
}
let person: Person = {
name: "John",
age: 30
};
Optional property: The age
property is optional thanks to the question mark (?:
).
interface Person {
name: string;
age?: number; // age is optional
}
let person: Person = {
name: "John"
};
Complex object:
interface Employee {
name: string;
age: number;
}
interface Company {
name: string;
employees: Employee[];
isActive: boolean;
}
let company: Company = {
name: "Tech Corp",
employees: [
{name: "Alice", age: 30},
{name: "Bob", age: 25}
],
isActive: true
};
Interface with function: You can also define functions within interfaces.
interface Person {
name: string;
age: number;
greet: () => string; // Definition of a function
}
let person: Person = {
name: "John",
age: 30,
greet: function() {
return `Hello, my name is ${this.name}`;
}
};
console.log(person.greet()); // Output: Hello, my name is John
Functions in TypeScript
Functions in TypeScript can be defined with parameter types and return types, improving clarity and control over the code. Here are some examples of how to declare and use functions:
Simple function with types: Defines the types of parameters and return type.
function add(a: number, b: number): number {
return a + b;
}
console.log(add(5, 3)); // Output: 8
Function with optional parameters: The lastName
parameter is optional thanks to the question mark (?:
).
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return firstName + " " + lastName;
} else {
return firstName;
}
}
console.log(buildName("John", "Doe")); // Output: John Doe
console.log(buildName("John")); // Output: John
Function with default parameters: The lastName
parameter has a default value.
function buildName(firstName: string, lastName: string = "Smith"): string {
return firstName + " " + lastName;
}
console.log(buildName("John", "Doe")); // Output: John Doe
console.log(buildName("John")); // Output: John Smith
Function with rest parameters: Uses the ...
operator to accept a variable number of parameters.
function buildName(firstName: string, ...restOfName: string[]): string {
return firstName + " " + restOfName.join(" ");
}
console.log(buildName("John", "Jacob", "Jingleheimer", "Schmidt"));
// Output: John Jacob Jingleheimer Schmidt
Functions with interfaces
in TypeScript
Interfaces can be used to type the objects passed as parameters to functions. Here are some examples:
Function accepting a typed object:
interface Person {
name: string;
age: number;
}
function greet(person: Person): string {
return `Hello, ${person.name}!`;
}
let user = { name: "John", age: 25 };
console.log(greet(user)); // Output: Hello, John!
Function with object and optional properties:
interface Person {
name: string;
age?: number; // age is optional
}
function greet(person: Person): string {
return `Hello, ${person.name}!`;
}
let user1 = { name: "John" };
let user2 = { name: "Mary", age: 30 };
console.log(greet(user1)); // Output: Hello, John!
console.log(greet(user2)); // Output: Hello, Mary!
Function with complex object:
interface Employee {
name: string;
age: number;
}
interface Company {
name: string;
employees: Employee[];
}
function listEmployees(company: Company): string {
return company.employees.map(emp => `${emp.name} (${emp.age})`).join(", ");
}
let myCompany: Company = {
name: "Tech Corp",
employees: [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 }
]
};
console.log(listEmployees(myCompany)); // Output: Alice (30), Bob (25)
Void Type in TypeScript
The void
type in TypeScript is used to represent the absence of a value, often as the return type for functions that do not return anything.
Function that does not return a value:
function warnUser(): void {
console.log("This is a warning message");
}
warnUser(); // Output: This is a warning message
The void
type is often used as the return type for functions that perform an action but do not return a value.
Union Types in TypeScript
Union types in TypeScript allow you to define a variable that can hold more than one type. This is useful when a variable can take values of different types. Here are some examples of how to use union types:
Variable with union types:
let id: number | string;
id = 10; // OK
id = "123"; // OK
// id = true; // Error: type 'boolean' is not assignable to type 'number | string'
Function with union type parameter:
function printId(id: number | string) {
console.log(`Your ID is: ${id}`);
}
printId(101); // Output: Your ID is: 101
printId("202"); // Output: Your ID is: 202
Union with complex types: You can combine objects and primitive types.
interface Dog {
bark: () => void;
}
interface Cat {
meow: () => void;
}
type Pet = Dog | Cat;
function makeSound(pet: Pet) {
if ('bark' in pet) {
pet.bark();
} else {
pet.meow();
}
}
let myDog: Dog = { bark: () => console.log("Woof!") };
let myCat: Cat = { meow: () => console.log("Meow!") };
makeSound(myDog); // Output: Woof!
makeSound(myCat); // Output: Meow!
Literal Types in TypeScript
Literal types in TypeScript allow you to specify exact values that a variable can take. This can be useful for defining more restrictive types and improving code safety. Here are some examples of how to use literal types:
String Literal Types:
type Direction = "up" | "down" | "left" | "right";
function move(direction: Direction) {
console.log(`Moving ${direction}`);
}
move("up"); // OK
move("left"); // OK
// move("forward"); // Error: type '"forward"' is not assignable to type 'Direction'
Numeric Literal Types:
type OneToFive = 1 | 2 | 3 | 4 | 5;
function rollDice(value: OneToFive) {
console.log(`Rolled a ${value}`);
}
rollDice(3); // OK
// rollDice(6); // Error: type '6' is not assignable to type 'OneToFive'
Boolean Literal Types:
type YesOrNo = "yes" | "no";
function answerQuestion(answer: YesOrNo) {
if (answer === "yes") {
console.log("You answered yes.");
} else {
console.log("You answered no.");
}
}
answerQuestion("yes"); // OK
answerQuestion("no"); // OK
// answerQuestion("maybe"); // Error: type '"maybe"' is not assignable to type 'YesOrNo'
Combining Literal Types with Union Types:
type Response = "success" | "error";
type StatusCode = 200 | 404 | 500;
function handleResponse(response: Response, code: StatusCode) {
console.log(`Response: ${response}, Status Code: ${code}`);
}
handleResponse("success", 200); // OK
handleResponse("error", 404); // OK
// handleResponse("error", 401); // Error: type '401' is not assignable to type 'StatusCode'
Literal types are useful for creating more precise and constrained types, improving code safety and readability. Combined with union types, they can define sets of possible values clearly and concisely.
any
Type in TypeScript
In TypeScript, the any
type is used to represent a variable that can hold any type of data. This type is useful when you do not know the type of a variable in advance or want to disable type checking for a specific variable. Here are some examples of how to use the any
type:
Variable of type any
:
let notSure: any = 4;
notSure = "maybe a string instead"; // OK
notSure = false; // OK
Function with parameter of type any
:
function logMessage(message: any): void {
console.log(message);
}
logMessage("Hello, world!"); // Output: Hello, world!
logMessage(42); // Output: 42
logMessage({ text: "This is a message" }); // Output: { text: "This is a message" }
Array of type any
: You can declare an array that can contain elements of any type.
let mixedArray: any[] = [1, "string", true];
console.log(mixedArray); // Output: [1, "string", true]
Although the any
type offers great flexibility, it is advisable to use it with caution. Excessive use of any
can reduce the benefits of TypeScript's type checking, making the code less robust and more difficult to maintain. In general, it is better to try to use more specific types whenever possible.Using too much any
can be considered a bad practice as it nullifies many of the benefits that TypeScript offers.
unknown
in TypeScript
The unknown
type is similar to the any
type but safer. When a variable is of type unknown
, you must check its type before you can use it. This provides more safety compared to using any
. Here are some examples of using the unknown
type:
Variable of type unknown
:
let notSure: unknown = 4;
notSure = "maybe a string instead"; // OK
notSure = false; // OK
Type checking before use:
function logValue(value: unknown): void {
if (typeof value === "string") {
console.log("String: " + value);
} else if (typeof value === "number") {
console.log("Number: " + value);
} else {
console.log("Unknown type");
}
}
logValue("Hello, world!"); // Output: String: Hello, world!
logValue(42); // Output: Number: 42
logValue(true); // Output: Unknown type
Using unknown
is a good practice when you are not sure of the type of a variable and want to enforce type checking before using it. This helps prevent errors and write safer code.
Type Assertion (as
) in TypeScript
In TypeScript, type assertion (type assertion
) allows you to tell the compiler to treat a variable as if it were of a specific type. This can be useful when you know more about the type of a variable than what the compiler can infer. Type assertion does not change the variable's type at runtime but helps the compiler understand the programmer's intentions.
Using as
:
let someValue: unknown = "this is a string";
let strLength: number = (someValue as string).length;
console.log(strLength); // Output: 16
In this example, someValue
is declared as unknown
. By using as
, we assert that someValue
is a string, allowing us to access the length
property.
Alternative use of <>
:
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;
console.log(strLength); // Output: 16
This example uses the angle bracket syntax (<>
) for type assertion, equivalent to using as
.
When to use type assertion:
- When working with data from external sources and you need to tell the compiler the expected type.
- When migrating existing JavaScript code to TypeScript and you know the types of the variables.
- When using a third-party library and you know better the return type of a function than what the compiler can infer.
Use type assertions with caution, as they tell the compiler to ignore standard type checking, potentially leading to runtime errors that are difficult to diagnose.
type
in TypeScript
In TypeScript, type
allows you to create aliases for complex types, making the code more readable and maintainable. You can use type
to define primitive types, unions, intersections, and even complex objects. Here are some examples of how to use the type
type:
Alias for primitive types:
type ID = number;
type Name = string;
let userId: ID = 123;
let userName: Name = "John Doe";
Alias for unions:
type Text = string | number;
let text: Text = "Hello";
text = 42; // OK
// text = true; // Error: type 'boolean' is not assignable to type 'string | number'
Alias for complex objects:
type Person = {
name: string;
age: number;
};
let person: Person = {
name: "John",
age: 30
};
Alias for functions:
type Greet = (name: string) => string;
let greet: Greet = function(name: string): string {
return `Hello, ${name}`;
};
console.log(greet("John")); // Output: Hello, John
Alias for intersections:
type Person = {
name: string;
age: number;
};
type Employee = Person & {
role: string;
};
let employee: Employee = {
name: "John",
age: 30,
role: "Developer"
};
Using type
in TypeScript allows you to define and easily reuse complex types, improving the readability and maintainability of the code.
Difference between type
and interface
In TypeScript, type
and interface
are two ways to define complex and structured types, but they have some differences in their functionality and usage.
Similarities between type
and interface
Both can be used to describe the shape of objects, including property and method types. Additionally, objects can implement both types defined with type
and interfaces defined with interface
.
Extension and Implementation
Interfaces can extend other interfaces and can be extended by other interfaces. They can also be implemented by classes.
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
class Labrador implements Dog {
name: string;
breed: string;
constructor(name: string, breed: string) {
this.name = name;
this.breed = breed;
}
}
Types can combine types using the &
(intersection) or |
(union) operators but cannot be extended in the same way that interfaces can.
type Animal = {
name: string;
};
type Dog = Animal & {
breed: string;
};
const myDog: Dog = {
name: "Fido",
breed: "Labrador"
};
Declaration Merging
Interfaces support "declaration merging", which means that multiple declarations with the same name automatically merge into a single interface.
interface User {
name: string;
}
interface User {
age: number;
}
const user: User = {
name: "John",
age: 30
};
Types do not support "declaration merging". If you attempt to declare two types with the same name, you get an error.
type User = {
name: string;
};
// Error: Duplicate identifier 'User'
type User = {
age: number;
};
Type Aliases
Types can create aliases for primitive types, unions, tuples, and other more complex constructions.
type StringOrNumber = string | number;
const value: StringOrNumber = "Hello"; // or 42
Classes in TypeScript
Classes in TypeScript are similar to those in JavaScript but with support for static typing. Classes can have properties, methods, constructors, and can implement interfaces and extend other classes. Here are some examples of how to use classes in TypeScript:
Definition of a simple class:
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
let person = new Person("John", 30);
console.log(person.greet()); // Output: Hello, my name is John and I am 30 years old.
Class with private properties and methods:
class Person {
private name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
let person = new Person("John", 30);
console.log(person.greet()); // Output: Hello, my name is John and I am 30 years old.
// console.log(person.name); // Error: property 'name' is private.
Class that implements an interface:
interface Greetable {
greet(): string;
}
class Person implements Greetable {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
let person = new Person("John", 30);
console.log(person.greet()); // Output: Hello, my name is John and I am 30 years old.
Class that extends another class:
class Employee extends Person {
role: string;
constructor(name: string, age: number, role: string) {
super(name, age);
this.role = role;
}
greet() {
return `Hello, my name is ${this.name}, I am ${this.age} years old and I work as a ${this.role}.`;
}
}
let employee = new Employee("Jane", 28, "Developer");
console.log(employee.greet());
// Output: Hello, my name is Jane, I am 28 years old and I work as a Developer.
Classes in TypeScript provide a clear and concise syntax for creating objects and managing their logic. With the addition of static typing, classes become even more powerful and useful for building robust and maintainable applications.
Enum in TypeScript
enum
in TypeScript allow you to define a set of constants with descriptive names. enum
can be numeric or string, and are useful for representing a set of related values. Here are some examples of how to use enums:
Numeric enums:
enum Direction {
Up = 1,
Down,
Left,
Right
}
let dir: Direction = Direction.Up;
console.log(dir); // Output: 1
In this example, the Direction
enum starts with the value 1 for Up
. The other enum members automatically increment by 1.
String enums:
enum Response {
Yes = "YES",
No = "NO"
}
function respond(recipient: string, message: Response): void {
console.log(`${recipient} responded with ${message}`);
}
respond("Alice", Response.Yes); // Output: Alice responded with YES
In this example, the Response
enum defines string constants, useful for representing fixed textual values.
Accessing enum
members:
enum Status {
New,
InProgress,
Done
}
let currentStatus: Status = Status.InProgress;
console.log(currentStatus); // Output: 1
console.log(Status[currentStatus]); // Output: InProgress
You can access enum members both by name and by value.
Using enum
in functions:
enum Status {
New,
InProgress,
Done
}
function updateStatus(status: Status): void {
console.log(`Updating status to: ${Status[status]}`);
}
updateStatus(Status.Done); // Output: Updating status to: Done
enum
are particularly useful when you want to work with a defined set of related values, improving code readability and maintainability.
Generics in TypeScript
Generics in TypeScript allow you to create reusable components that work with various types of data. By using generics, you can create functions, classes, and interfaces that are not limited to a single data type. Here are some examples of how to use generics:
Generic function:
//In TypeScript, T is a convention to indicate a generic type,
//while K is a convention to indicate a key of a generic object (K extends keyof T)
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>("Hello, world!");
let output2 = identity<number>(42);
console.log(output1); // Output: Hello, world!
console.log(output2); // Output: 42
In this example, the identity
function uses a generic parameter T
, which allows passing and returning values of any type.
Generic array:
function logArrayElements<T>(elements: T[]): void {
elements.forEach(element => console.log(element));
}
logArrayElements<number>([1, 2, 3]); // Output: 1, 2, 3
logArrayElements<string>(["a", "b", "c"]); // Output: a, b, c
Here, the logArrayElements
function uses a generic array T[]
, allowing passing arrays of any type.
Generic class:
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
constructor(zeroValue: T, addFunction: (x: T, y: T) => T) {
this.zeroValue = zeroValue;
this.add = addFunction;
}
}
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
console.log(myGenericNumber.add(5, 10)); // Output: 15
In this example, the GenericNumber
class uses a generic parameter T
to define the properties and methods of the class.
Generic interface:
interface Pair<T, U> {
first: T;
second: U;
}
let pair: Pair<string, number> = { first: "hello", second: 42 };
console.log(pair); // Output: { first: "hello", second: 42 }
Here, the Pair
interface uses two generic parameters T
and U
, allowing creating pairs of values of any type.
Using generics with constraints:
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): void {
console.log(arg.length);
}
logLength("hello"); // Output: 5
logLength([1, 2, 3]); // Output: 3
// logLength(42); // Error: type 'number' does not have the property 'length'
In this example, the generic T
is constrained by the Lengthwise
interface, which requires the type to have a length
property.
Generics are powerful tools that allow you to write flexible and reusable code. With generics, you can create components that work with a variety of data types, improving the robustness and maintainability of your code.
Narrowing in TypeScript
In TypeScript, "narrowing" refers to the process of narrowing the type of a variable from a more generic type to a more specific one. Let's look at some main techniques.
typeof
Using typeof
, we can narrow the type based on the primitive type.
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(`String: ${value}`);
} else {
console.log(`Number: ${value}`);
}
}
instanceof
Using instanceof
, we can narrow the type based on its instance.
class Dog { bark() { console.log("Woof!"); } }
class Cat { meow() { console.log("Meow!"); } }
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
Equality Check
We can narrow the type by comparing it with a specific value.
type Pet = "dog" | "cat";
function getPetSound(pet: Pet) {
if (pet === "dog") {
return "Woof!";
} else {
return "Meow!";
}
}
Custom Type Guards
We create custom functions to narrow the type.
function isString(value: any): value is string {
return typeof value === "string";
}
function printValue(value: string | number) {
if (isString(value)) {
console.log(`String: ${value}`);
} else {
console.log(`Number: ${value}`);
}
}
Utility Types in TypeScript
TypeScript provides several predefined utility types that allow you to transform and manipulate types flexibly. These utility types can simplify working with complex types and increase code reusability. Here is an overview of the most useful ones:
Partial<T>
Makes all properties in a type optional.
interface Person {
name: string;
age: number;
}
function updatePerson(person: Partial<Person>) {
// The function can accept a Person object with partially defined properties
}
updatePerson({ name: "John" }); // OK
updatePerson({ age: 30 }); // OK
updatePerson({}); // OK
Required<T>
Makes all properties in a type required.
interface Person {
name?: string;
age?: number;
}
function printPerson(person: Required<Person>) {
// The function requires a Person object with all properties defined
}
printPerson({ name: "John", age: 30 }); // OK
// printPerson({ name: "John" }); // Error: property 'age' is missing
Readonly<T>
Makes all properties in a type read-only.
interface Person {
name: string;
age: number;
}
let readonlyPerson: Readonly<Person> = { name: "John", age: 30 };
// readonlyPerson.name = "Doe"; // Error: 'name' is read-only
Record<K, T>
Creates a type object with a set of properties K
of type T
.
type Role = "admin" | "user" | "guest";
interface Person {
name: string;
age: number;
}
const people: Record<Role, Person> = {
admin: { name: "Alice", age: 25 },
user: { name: "Bob", age: 30 },
guest: { name: "Charlie", age: 35 }
};
Pick<T, K>
Creates a type by picking a subset of properties from an existing type.
interface Person {
name: string;
age: number;
address: string;
}
type PersonNameAndAge = Pick<Person, "name" | "age">;
const person: PersonNameAndAge = {
name: "John",
age: 30
// address: "123 Street" // Error: 'address' is not allowed
};
Omit<T, K>
Creates a type by omitting a subset of properties from an existing type.
interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, "address">;
const person: PersonWithoutAddress = {
name: "John",
age: 30
// address: "123 Street" // Error: 'address' is not allowed
};
Exclude<T, U>
Removes types from U
from T
.
type AllTypes = string | number | boolean;
type StringOrNumber = Exclude<AllTypes, boolean>;
// StringOrNumber is equivalent to 'string | number'
Extract<T, U>
Extracts types that are present in both T
and U
.
type AllTypes = string | number | boolean;
type StringOrBoolean = Extract<AllTypes, string | boolean>;
// StringOrBoolean is equivalent to 'string | boolean'
NonNullable<T>
Removes null
and undefined
from a type.
type NullableTypes = string | number | null | undefined;
type NonNullableTypes = NonNullable<NullableTypes>;
// NonNullableTypes is equivalent to 'string | number'
These utility types provide powerful tools for working with types in TypeScript, improving the flexibility and maintainability of your code.
Table of Contents
- Introduction
- Installation of TypeScript
- Compiling TypeScript
- What is tsc and Transpilation
- Primitive Types in TypeScript
- Arrays in TypeScript
- Objects in TypeScript
- Interfaces in TypeScript
- Functions in TypeScript
- Functions with Interfaces in TypeScript
- Void Type in TypeScript
- Union Types in TypeScript
- Literal Types in TypeScript
- Any Type in TypeScript
- Unknown Type in TypeScript
- Type Assertion (as) in TypeScript
- type in TypeScript
- Difference between Type and Interface
- Classes in TypeScript
- Enums in TypeScript
- Generics in TypeScript
- Narrowing in TypeScript
- Utility Types in TypeScript