My List of Uncommon But Useful Typescript Types

A few uncommon but useful typescript types - with examples

Photo by TR Davis on Unsplash


Typescript is awesome! It allows developers to use primitive and user-defined types in javascript. Lately, more and more javascript frameworks are providing firsthand Typescript support; Angular, Vue , NodeGUI and many more.

If you haven’t tried it out yet, I would highly recommend it. You can get started here .

Disclaimer: This tutorial assumes basic knowledge of javascript and typescript. If you’re not familiar with them, use the resources provided above to learn more before continuing with the rest of the article!

Let us now look at a few different “types” in typescript and how they can be used.

Optional types

Most readers probably know this type but it is included in the article for the sake of completeness.

Say you’re creating a type for an object out of which a few keys are optional. For example, let us create a type User with two keys, name and type . Out of the two, we need only the name field to be required. We could create it as follows:

type User = {
   name: string,
   type?: string //optional key denoted by the "?"

Nested types

In typescript, we can use existing types, primitive or user-defined, while creating newer types. Let us look at an example of adding details to the User type from the previous example.

Assume that we already have a UserDetails type as follows:

type UserDetails = {
   address: string,
   age: number,
   height: number

We can use this type in our User type as follows:

type User = {
   name: string,
   type?: string,
   details: UserDetails // Using an existing type in a new type

Generic Types

Imagine two types having the same structure but for one different key. In such a case, we could create two separate types and get away with it. What we could also do is “parameterize” a base type and create new types from it. Typescript lets you create types that accept one or more parameters mentioned within <> braces and use them anywhere inside your type.

For example, consider a type Product that took a name , and optional type and a details object which is of type ProductDetails given below:

type ProductDetails = {
   price: number,
   weight: number

The structure of our Product type is very similar to our User type except that they both have different structures for the details key. We can remedy that by creating a new base type:

type BaseEntity<TDetails> = {
   name: string,
   type?: string,
   details: TDetails
Note: By convention, parameters to generic types are preceded by a “T”

Now, we can create User and Product as follows:

type User = BaseEntity<UserDetails>;type Product = BaseEntity<ProductDetails>;

Pick/Omit Types

Imagine building these types for a web-app that consists of two pages; The first where you display all the Product s and the second where you see the detailed view of the Product clicked on.

In such a case, you’d need two types, the Product type for the detailed view and the ProductPreview type for the “all products” page. The ProductPreview type does not need the product’s details .

Instead of creating a completely new type, typescript allows you to create a new type by “Picking” existing keys from the existing type, Product .

type ProductPreview = Pick<Product, "name" | "type">;

The same effect can be achieved by “omitting” the details key from the Product type:

type ProductPreview = Omit<Product, "details">;

Function types

In typescript, you can create a type, not only for normal objects, but also for functions. In a situation where we have a family of functions that have the same return type, this can be used.

Say, we have a flight of functions that perform string manipulations; naturally, they all return strings. Normally, we’d have something like the following for each function:

const func1 = (): string => { // code }const func2 = (): string => { // more code }

As you can see, we are repeating ourselves everytime we write the return type of the function. we can remedy this by creating a type that each of these functions can reuse:

type StringManipulator = () => stringconst func1: StringManipulator = () => { // code }const func2: StringManipulator = () => { // more code }

This may not feel significant now. So let’s take a more complex example. Say, we know that the first parameter of these functions is always going to be an instance of class Test . The functions can take any number of additional parameters. Let’s create a type for these functions:

type StandardFunction = (
   instance: Test,
   ...otherArgs: Array<any>
) => stringconst func1: StandardFunction = (inst) => { //code }const func2: StandardFunction = (inst, text:string) => {
   // more code

Now, in case we know only the first argument for each function, but the type of the first argument is not the same for all the functions, we can combine the generic types with the function types:

type GenericFunction<ArgType> = (
   instance: ArgType,
   ...otherArgs: Array<any>
) => stringconst func1: GenericFunction<Test> = (inst) => { //code }const func2: GenericFunction<Test2> = (inst, text:string) => {
   // more code 

More powerful now, isn’t it?

These are just a few uncommon typescript types that I came across/built. There’s so much more for readers to explore. The links below should prove beneficial for the same.

Hope you found this interesting. Please write your comment/doubts/suggestions below :point_down:

Cheers :coffee:️