DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Build Your Own Shopping Cart With React Hooks
  • Mule 4 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Adding Two Hours in DataWeave: Mule 4
  • From Zero to Meme Hero: How I Built an AI-Powered Meme Generator in React

Trending

  • Your Ultimate Website QA Checklist
  • Platform Engineering for Cloud Teams
  • Build Your First AI Model in Python: A Beginner's Guide (1 of 3)
  • Beyond Linguistics: Real-Time Domain Event Mapping with WebSocket and Spring Boot
  1. DZone
  2. Data Engineering
  3. Data
  4. TypeScript: Useful Features

TypeScript: Useful Features

Some advanced constructs may require a learning curve, but can significantly bolster your type safety. This article introduces you to some of these advanced features.

By 
Vasyl Mysiura user avatar
Vasyl Mysiura
·
Sep. 22, 23 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
6.7K Views

Join the DZone community and get the full member experience.

Join For Free

Nowadays, it’s difficult to imagine a serious JavaScript-based application without a TypeScript superset. Interfaces, tuples, generics, and other features are well-known among TypeScript developers. While some advanced constructs may require a learning curve, they can significantly bolster your type safety. This article aims to introduce you to some of these advanced features.

Type Guards

Type guards help us to get info about a type within a conditional block. There are a few simple ways to check the type using in, typeof, instanceof operators, or using equality comparison (===).

In this section, I’d like to pay more attention to user-defined type guards. This guard serves as a simple function that returns a boolean value. In other words, the return value is a type predicate.
Let’s take a look at the example when we have base user info and user with additional details:

JavaScript
 
type User = { name: string };
type DetailedUser = { 
  name: string; 
  profile: { 
    birthday: string
  }
}

function isDetailedUser(user: User | DetailedUser) {
  return 'profile' in user;
}

function showDetails(user: User | DetailedUser) {
if (isDetailedUser(user)) {
  console.log(user.profile); // Error: Property 'profile' does not exist on      type 'User | DetailedUser'.
          }
}


The isDetailedUser function returns a boolean value, but it does not identify this function as a boolean that “defines the object type.”

In order to achieve the desired result, we need a little bit of update isDetailedUser function using ““user is DetailedUser” construction

JavaScript
 
function isDetailedUser(user: User | DetailedUser): user is DetailedUser {
  return 'profile' in user;
}


Indexed Access Types

There may be the case in your app when you have a large object type and you want to create a new type, that uses a part of the original one. For example, part of our app requires only a user profile. User[‘profile’] extracts the desired type and assigns it to the UserProfile type.

JavaScript
 
type User = {
  id: string;
  name: string;
  surname: string;
  profile: {
    birthday: string;
  }
}

type UserProfile = User['profile'];


What if we want to create a type based on a few properties? In this case, you can use a built-in type called Pick.

JavaScript
 
type FullName = Pick<User, 'name' | 'surname'>; // { name: string; surname: string }


There are many other utility types, such as Omit, Exclude, and Extract, which may be helpful for your app. At first sight, all of them are kind of indexed types, but actually, they are built on Mapped types.

Indexed Types With an Array

You might have met the case when an app provided you with a union type, such as:

JavaScript
 
type UserRoleType = ‘admin’ | ‘user’ | ‘newcomer’;


Then, in another part of the app, we fetch user data and check its role. For this case, we need to create an array:

JavaScript
 
const ROLES: UserRoleType[] = [‘admin’, ‘user’, ‘newcomer’];
ROLES.includes(response.user_role);


Looks tiring, doesn't it? We need to repeat union-type values inside our array. It would be great to have a feature to retrieve a type from an existing array to avoid duplication. Fortunately, indexed types help here as well.

First of all, we need to declare our array using a const assertion to remove the duplication and make a read-only tuple.

JavaScript
 
const ROLES = [‘admin’, ‘user’, ‘newcomer’] as const;


Then, using the typeof operator and number type, we create a union type based on the array value.

JavaScript
 
type RolesType = typeof ROLES[number]; // ‘admin’ | ‘‘user’ | ‘‘newcomer’;


You may be confused about this solution, but as you may know, arrays are object-based constructions with numeric keys. That’s why, in this example, number is used as the index access type.

Conditional Types and Infer Keyword

Conditional types define a type that depends on the condition. Usually, they are used along with generics. Depending on the generic type (input type), construction chooses the output type.

For example, the built-in NonNullable TypeScript type is built on conditional types.

JavaScript
 
type NonNullable<T> = T extends null | undefined ? never : T
type One = NonNullable<number>; // number
type Two = NonNullable<undefined>; // never


The infer keyword is used with conditional types and can not be used outside of the ‘extends’ clause. It serves as a ‘type variable creator.’

I think it will be easier for you to understand it by looking at the real example. 

Case: retrieve async function result type.

JavaScript
 
const fetchUser = (): Promise<{ name: string }> => { /* implementation */ }


The easiest solution is to import the type declaration and assign it to the variable. Unfortunately, there are cases when result declaration is written inside the function, as in the example above. 

This problem may be resolved in two steps:

  1.  The Awaited utility type was introduced in TypeScript 4.5. For learning purposes, let’s look at the simplified variant.
JavaScript
 
export type Awaited<T> = T extends Promise<infer U> ? U : T;


Using conditional types and infer keyword, we “pull out” the promised type and assign it to the Uname. It’s a kind of type variable declaration. If the passed type is acceptable with PromiseLike generic, construction returns the original type saved to the U name.

2. Get value from the async function.

Using built-in ReturnType that extracts the return type of function and our Awaited type, we achieve the desired result:

JavaScript
 
export type Awaited ReturnType<T> = Awaited<Return Type<T>>;


I hope you found this article useful for yourself. Have fun coding!

Data structure JavaScript TypeScript Data Types

Opinions expressed by DZone contributors are their own.

Related

  • Build Your Own Shopping Cart With React Hooks
  • Mule 4 DataWeave(1.x) Script To Resolve Wildcard Dynamically
  • Adding Two Hours in DataWeave: Mule 4
  • From Zero to Meme Hero: How I Built an AI-Powered Meme Generator in React

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!