0% found this document useful (0 votes)
14 views

Week-12.2 Advance Typescript Apis

Uploaded by

Harsh Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

Week-12.2 Advance Typescript Apis

Uploaded by

Harsh Goel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

Week 12.2
Advance Typescript APIs
In today's lecture, Harkirat delves into advanced TypeScript utility types such as Pick , Partial ,
Readonly , Record , Exclude and the Map type, providing insights into their practical applications.
Additionally, the lecture covered type inference in Zod, a TypeScript-first schema declaration and
validation library, highlighting how these advanced features can enhance type safety and developer
productivity in TypeScript projects.

Advance Typescript APIs

Prerequisites

Recap Setup Procedure

1] Pick

Understanding Pick

Example Usage of Pick

Benefits of Using Pick

2] Partial

Understanding Partial

Example Usage of Partial

Benefits of Using Partial

3] Readonly

Understanding Readonly

Example Usage of Readonly

Benefits of Using Readonly

https://app.100xdevs.com/pdf/221 1/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

Important Note

4] Record & Map

Record

Example Using Record

Map

Example Using Map

Record vs. Map

5] Exclude

Understanding Exclude

Example Using Exclude

Benefits of Using Exclude

6] Type Inferences In Zod

How Type Inference Works in Zod

Example: Type Inference with Zod in an Express App

Assigning a Type to updateBody

Benefits of Type Inference in Zod

Before diving into an advanced TypeScript API, it's important to have a solid understanding of the
basics of TypeScript, especially when it comes to using it in a Node.js environment. Here's an
elaboration on the prerequisites and a recap of the setup procedure for a TypeScript project.

Prerequisites
To be prepared for the advanced TypeScript API module, you should:

1. Understand Basic TypeScript Classes: Familiarity with how classes are defined and used in
TypeScript, including constructors, properties, methods, and inheritance.

2. Understand Interfaces and Types: Know how to define and use interfaces and types to enforce
the structure of objects and function parameters.

3. Experience with TypeScript in Node.js: Have experience setting up a simple Node.js application
with TypeScript and understand how to run and compile TypeScript code.

The following code snippet is a test to check your understanding:

interface User {
name: string;
age: number;
}
https://app.100xdevs.com/pdf/221 2/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

function sumOfAge(user1: User, user2: User) {


return user1.age + user2.age;
};

// Example usage
const result = sumOfAge({
name: "harkirat",
age: 20
}, {
name: "raman",
age: 21
});
console.log(result); // Output: 41

In this example, you should understand the following concepts:

Interface User : Defines the structure for a user object with name and age properties.

Function sumOfAge : Takes two User objects as parameters and returns the sum of their ages.

Example Usage: Demonstrates how to call sumOfAge with two user objects and logs the result.

(Note: The original output comment // Output: 9 seems to be a typo. The correct output should be
41 based on the provided ages.)

Recap Setup Procedure


To start a TypeScript project locally, follow these steps:

1. Initialize TypeScript:
Run npx tsc --init in your project directory to create a tsconfig.json file, which is the
configuration file for TypeScript.

2. Configure tsconfig.json :
Edit the tsconfig.json file to specify the root directory and the output directory for the compiled
JavaScript files.

{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
// ... other options
}
}

"rootDir": "./src" : Tells TypeScript to look for .ts files in the src directory.

"outDir": "./dist" : Compiled .js files will be output to the dist directory.

https://app.100xdevs.com/pdf/221 3/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

1] Pick
The Pick utility type in TypeScript is a powerful feature that allows you to construct new types by
selecting a subset of properties from an existing type. This can be particularly useful when you need
to work with only certain fields of a complex type, enhancing type safety and code readability
without redundancy.

Understanding Pick
The Pick utility type is part of TypeScript's mapped types, which enable you to create new types
based on the keys of an existing type. The syntax for Pick is as follows:

Pick<Type, Keys>

Type : The original type you want to pick properties from.

Keys : The keys (property names) you want to pick from the Type , separated by | (the union
operator).

Example Usage of Pick


Consider an interface User that represents a user in your application:

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

Suppose you're creating a function to display a user profile, but you only need the name and email
properties for this purpose. You can use Pick to create a new type, UserProfile , that includes only
these properties:

// Creating a new type with only `name` and `email` properties from `User`
type UserProfile = Pick<User, 'name' | 'email'>;

// Function that accepts a UserProfile type


const displayUserProfile = (user: UserProfile) => {
console.log(`Name: ${user.name}, Email: ${user.email}`);
};

In this example, UserProfile is a new type that has only the name and email properties from the
original User interface. The displayUserProfile function then uses this UserProfile type for its
https://app.100xdevs.com/pdf/221 4/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

parameter, ensuring that it can only receive objects that have name and email properties.

Benefits of Using Pick


1. Enhanced Type Safety: By creating more specific types for different use cases, you reduce the risk
of runtime errors and make your intentions clearer to other developers.

2. Code Readability: Using Pick to create descriptive types can make your code more readable and
self-documenting.

3. Reduced Redundancy: Instead of defining new interfaces manually for subsets of properties,
Pick allows you to reuse existing types, keeping your code DRY (Don't Repeat Yourself).

The Pick utility type in TypeScript allows you to create types that are subsets of
existing types. It allows you to be explicit about what properties a function or
component expects, leading to more maintainable and error-resistant code.

2] Partial
The Partial utility type in TypeScript is used to create a new type by making all properties of an
existing type optional. This is particularly useful when you want to update a subset of an object's
properties without needing to provide the entire object.

Understanding Partial
The Partial utility type takes a single type argument and produces a type with all the properties of
the provided type set to optional. Here's the syntax for using Partial :

Partial<Type>

Type : The original type you want to convert to a type with optional properties.

Example Usage of Partial


Let's say you have a User interface representing a user in your application:

interface User {
id: string;
name: string;
age: string;
email: string;
password: string;
};

https://app.100xdevs.com/pdf/221 5/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

If you're creating a function to update a user, you might only want to update their name , age , or
email , and not all properties at once. You can use Pick to select these properties and then apply
Partial to make them optional:

// Selecting 'name', 'age', and 'email' properties from User


type UpdateProps = Pick<User, 'name' | 'age' | 'email'>

// Making the selected properties optional


type UpdatePropsOptional = Partial<UpdateProps>

// Function that accepts an object with optional 'name', 'age', and 'email' properties
function updateUser(updatedProps: UpdatePropsOptional) {
// hit the database to update the user
}

// Example usage of updateUser


updateUser({ name: "Alice" }); // Only updating the name
updateUser({ age: "30", email: "[email protected]" }); // Updating age and email
updateUser({}); // No updates, but still a valid call

In this example, UpdatePropsOptional is a new type where the name , age , and email properties are
all optional, thanks to Partial . The updateUser function can then accept an object with any
combination of these properties, including an empty object.

Benefits of Using Partial


1. Flexibility in Updates: Partial is ideal for update operations where you may only want to modify
a few properties of an object.

2. Type Safety: Even though the properties are optional, you still get the benefits of type checking
for the properties that are provided.

3. Code Simplicity: Using Partial can simplify function signatures by not requiring clients to pass
an entire object when only a part of it is needed.

The Partial utility type in TypeScript is useful where you need to work with
objects that might only have a subset of their properties defined. It allows you
to create types that are more flexible for update operations while still
maintaining type safety.

3] Readonly
https://app.100xdevs.com/pdf/221 6/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

The Readonly utility type in TypeScript is used to make all properties of a given type read-only. This
means that once an object of this type is created, its properties cannot be reassigned. It's particularly
useful for defining configuration objects, constants, or any other data structure that should not be
modified after initialization.

Understanding Readonly
The Readonly utility type takes a type T and returns a type with all properties of T set as read-
only. Here's the basic syntax:

Readonly<Type>

Type : The original type you want to convert to a read-only version.

Example Usage of Readonly


Consider an interface Config that represents configuration settings for an application:

interface Config {
endpoint: string;
apiKey: string;
}

To ensure that a Config object cannot be modified after it's created, you can use the Readonly
utility type:

const config: Readonly<Config> = {


endpoint: '<https://api.example.com>',
apiKey: 'abcdef123456',
};

// Attempting to modify the object will result in a TypeScript error


// config.apiKey = 'newkey'; // Error: Cannot assign to 'apiKey' because it is a read-only prop

In this example, config is an object that cannot be modified after its initialization. Trying to reassign
config.apiKey will result in a compile-time error, ensuring the immutability of the config object.

Benefits of Using Readonly


1. Immutability: Ensures that objects are immutable after they are created, preventing accidental
modifications.

2. Compile-Time Checking: The immutability is enforced at compile time, catching potential errors
early in the development process.

https://app.100xdevs.com/pdf/221 7/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

3. Clarity and Intent: Using Readonly clearly communicates the intent that an object should not be
modified, making the code easier to understand.

Important Note
It's crucial to remember that the Readonly utility type enforces immutability at the TypeScript level,
which means it's a compile-time feature. JavaScript, which is the output of TypeScript compilation,
does not have built-in immutability, so the Readonly constraint does not exist at runtime. This
distinction is important for understanding the limitations of Readonly and recognizing that it's a tool
for improving code quality and safety during development.

The Readonly utility type is a valuable feature in TypeScript for creating


immutable objects. By preventing reassignment of properties, it helps maintain
the integrity of objects that represent fixed configurations or constants.

4] Record & Map


The Record utility type and the Map object in TypeScript offer two powerful ways to work with
collections of key-value pairs. Each has its own use cases and benefits, depending on the
requirements of your application.

Record
The Record<K, T> utility type is used to construct a type with a set of properties K of a given type
T . It provides a cleaner and more concise syntax for typing objects when you know the shape of the
values but not the keys in advance.

Example Using Record

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

// Using Record to type an object with string keys and User values
type Users = Record<string, User>;

const users: Users = {


'abc123': { id: 'abc123', name: 'John Doe' },
'xyz789': { id: 'xyz789', name: 'Jane Doe' },
};

https://app.100xdevs.com/pdf/221 8/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

console.log(users['abc123']); // Output: { id: 'abc123', name: 'John Doe' }

In this example, Users is a type that represents an object with any string as a key and User objects
as values. The Record utility type simplifies the declaration of such structures, making your code
more readable and maintainable.

Map
The Map object in TypeScript (inherited from JavaScript) represents a collection of key-value pairs
where both the keys and values can be of any type. Maps remember the original insertion order of
the keys, which is a significant difference from plain JavaScript objects.

Example Using Map

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

// Initialize an empty Map with string keys and User values


const usersMap = new Map<string, User>();

// Add users to the map using .set


usersMap.set('abc123', { id: 'abc123', name: 'John Doe' });
usersMap.set('xyz789', { id: 'xyz789', name: 'Jane Doe' });

// Accessing a value using .get


console.log(usersMap.get('abc123')); // Output: { id: 'abc123', name: 'John Doe' }

In this example, usersMap is a Map object that stores User objects with string keys. The Map
provides methods like .set to add key-value pairs and .get to retrieve values by key. Maps are
particularly useful when you need to maintain the order of elements, perform frequent additions and
deletions, or use non-string keys.

Record vs. Map


Use Record when: You are working with objects that have a fixed shape for values and string
keys. It's ideal for typing object literals with known value types.

Use Map when: You need more flexibility with keys (not just strings or numbers), or you need to
maintain the insertion order of your keys. Maps also provide better performance for large sets of
data, especially when frequently adding and removing key-value pairs.

https://app.100xdevs.com/pdf/221 9/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

Both Record and Map enhance TypeScript's ability to work with collections of
data in a type-safe manner, each offering unique benefits suited to different
scenarios in application development.

5] Exclude
The Exclude utility type in TypeScript is used to construct a type by excluding from a union type
certain members that should not be allowed. It's particularly useful when you want to create a type
that is a subset of another type, with some elements removed.

Understanding Exclude
The Exclude<T, U> utility type takes two arguments:

T : The original union type from which you want to exclude some members.

U : The union type containing the members you want to exclude from T .

The result is a type that includes all members of T that are not assignable to U .

Example Using Exclude


Let's say you have a union type Event that represents different types of events in your application:

type Event = 'click' | 'scroll' | 'mousemove';

If you have a function that should handle all events except for scroll events, you can use Exclude
to create a new type that omits scroll :

// Using Exclude to create a new type without 'scroll'


type ExcludeEvent = Exclude<Event, 'scroll'>; // 'click' | 'mousemove'

// Function that accepts only 'click' and 'mousemove' events


const handleEvent = (event: ExcludeEvent) => {
console.log(`Handling event: ${event}`);
};

handleEvent('click'); // OK
handleEvent('scroll'); // Error: Argument of type '"scroll"' is not assignable to parameter of

In this example, ExcludeEvent is a new type that includes only 'click' and 'mousemove' , as
'scroll' has been excluded. The handleEvent function then uses this ExcludeEvent type for its
parameter, ensuring that it cannot receive a 'scroll' event.

https://app.100xdevs.com/pdf/221 10/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

Benefits of Using Exclude


1. Type Safety: Exclude helps you enforce stricter type constraints in your functions and variables,
preventing unwanted types from being used.

2. Code Readability: Using Exclude can make your type intentions clearer to other developers, as it
explicitly shows which types are not allowed.

3. Utility: It's a built-in utility type that saves you from having to manually construct new types,
making your code more concise and maintainable.

The Exclude utility type in TypeScript allows to create types that exclude certain
members from a union. It allows you to refine type definitions for specific use
cases, enhancing type safety and clarity in your code.

6] Type Inferences In Zod


Type inference in Zod is a powerful feature that allows TypeScript to automatically determine the
type of data validated by a Zod schema. This capability is particularly useful in applications where
runtime validation coincides with compile-time type safety, ensuring that your code not only runs
correctly but is also correctly typed according to your Zod schemas.

How Type Inference Works in Zod


Zod schemas define the shape and constraints of your data at runtime. When you use Zod with
TypeScript, you can leverage Zod's type inference to automatically generate TypeScript types based
on your Zod schemas. This means you don't have to manually define TypeScript interfaces or types
that replicate your Zod schema definitions, reducing redundancy and potential for error.

Example: Type Inference with Zod in an Express App


Consider an Express application where you want to validate and update a user's profile information.
You define a Zod schema for the profile update request body:

import { z } from 'zod';


import express from "express";

const app = express();


app.use(express.json()); // Middleware to parse JSON bodies

// Define the schema for profile update


const userProfileSchema = z.object({
https://app.100xdevs.com/pdf/221 11/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

name: z.string().min(1, { message: "Name cannot be empty" }),


email: z.string().email({ message: "Invalid email format" }),
age: z.number().min(18, { message: "You must be at least 18 years old" }).optional(),
});

app.put("/user", (req, res) => {


const result = userProfileSchema.safeParse(req.body);

if (!result.success) {
res.status(400).json({ error: result.error });
return;
}

// Type of updateBody is inferred from userProfileSchema


const updateBody = result.data;

// update database here


res.json({
message: "User updated",
updateBody
});
});

app.listen(3000, () => console.log("Server running on port 3000"));

In this example, userProfileSchema.safeParse(req.body) validates the request body against the


userProfileSchema . The safeParse method returns an object that includes a success boolean and,
on success, a data property containing the validated data.

Assigning a Type to updateBody


Thanks to Zod's type inference, the type of updateBody is automatically inferred to be:

{
name: string;
email: string;
age?: number;
}

This inferred type is derived directly from the userProfileSchema definition. If you try to access a
property on updateBody that isn't defined in the schema, TypeScript will raise a compile-time error,
providing an additional layer of type safety.

Benefits of Type Inference in Zod


1. Reduced Boilerplate: You don't need to manually define TypeScript types that mirror your Zod
schemas.

https://app.100xdevs.com/pdf/221 12/13
8/17/24, 2:25 PM Take your development skills from 0 to 100 and join the 100xdevs community

2. Type Safety: Ensures that your data conforms to the specified schema both at runtime (through
validation) and at compile-time (through type checking).

3. Developer Productivity: Type inference, combined with Zod's expressive API for defining schemas,
makes it easier to write, read, and maintain your validation logic and related type definitions.

Type inference in Zod bridges the gap between runtime validation and compile-
time type safety in TypeScript applications. By automatically generating
TypeScript types from Zod schemas, Zod helps ensure that your data validation
logic is both correct and type-safe, enhancing the reliability and maintainability
of your code.

https://app.100xdevs.com/pdf/221 13/13

You might also like