Generic Functions in TypeScript

Learn via video courses
Topics Covered

Overview

Building components that are not just well-defined and consistent in their APIs, but also reusable, is an important element of software engineering. Components that can function on today's data as well as tomorrow's data will provide you with the most versatile capabilities for constructing massive software systems. One of the features that typescript provides is Generic Functions.

Introduction

A generic function is a function that has type arguments. Actual types are used instead of type arguments when called. New Generic Functions in typescript can be written directly in CLIPS using the defgeneric and defmethod constructs. Generic Functions in typescript, like deffunctions, may be used to define new procedural code directly in CLIPS and can be invoked just like any other function.

Generics, the ability to design a component that can function over several types rather than a single one, is one of the key tools in the toolkit for creating reusable components in languages such as C# and Java. This enables users to utilize these components while also using their kinds.

Generic Functions in typescript, on the other hand, are far more powerful since they can do different things based on the types (or classes) and amount of arguments. For example, a +i operator may be developed that does text concatenation while still doing mathematical addition on integers. Generic Functions in typescript are made up of several components called methods, each of which handles a particular set of parameters for the generic function. A generic function with several methods is said to be overloaded.

As implicit methods, Generic Functions in typescript can contain system functions and user-defined external functions. Overloading the '+' operator to handle strings, for example, consists of two methods :

  • An explicit (user-defined) one handling string concatenation, and
  • An implicit one that is the system function handling numerical addition.

Deffunctions, on the other hand, may not be methods of Generic Functions in typescript because they are already subsumed by Generic Functions in typescript. Deffunctions are solely supplied to allow simple new functions to be inserted directly in CLIPS without fear of overloading. A generic function, for example, with only one method that limits the number of arguments is equal to a deffunction.

In most circumstances, generic function methods are not explicitly invoked. CLIPS identifies a generic function call and utilizes the generic function's inputs to locate and run the relevant method. This procedure is known as generic dispatch. With this now we have a basic knowledge of Generic Functions in typescript, Now let’s see Generic Functions in typescript :

What are Generic Functions in Typescript?

TypeScript Generics is a technology that allows you to make reusable components. It generates a component that can operate with many data types rather than just one. It enables users to utilize these components while also using their kinds. Generics guarantee that the software is both adaptable and scalable in the long run.

Generics ensure type safety without sacrificing performance or efficiency. TypeScript uses generics in conjunction with the type variable to denote types. Generic Functions in typescript have the same type as non-Generic Functions in typescript, with the type arguments provided first, as in function declarations.

To make it highly typed, we must introduce a type parameter in generics between the open () and close (>) brackets. Generics make use of a particular type variable <T> to denote types. The generics collections only include items of the same type.

We may construct generic classes, Generic Functions in typescript, generic methods, and generic interfaces with TypeScript. Generics in TypeScript is quite similar to generics in C# and Java.

Generic Syntax

Generics exist inside angle brackets in TypeScript code, in the format <T>, where T denotes a passed-in type. <T> represents a generic type T. T will serve in this situation similarly to arguments in functions, as placeholders for a type that will be defined when an instance of the structure is produced. As a result, the generic types supplied inside angle brackets are sometimes known as generic type parameters or simply type parameters. Multiple generic types, such as <T, K, A>, can also appear in a single specification.

Generics can exist in functions, types, classes, and interfaces, among other places. Each of these structures will be discussed more in this lesson, but for the time being, a function will be used as an example to demonstrate the fundamental syntax of generics.

Consider the following scenario : you have a JavaScript method that takes two parameters : an object and an array of keys. The function will produce a new object that is based on the original but has just the keys you specify :

The sample() method iterates through the y array and constructs a new object with the y supplied in the array.

Here's an example of how to employ the function :

This establishes an object language and then uses the sample() method to extract the age and extension properties. The following is the value of Properties :

To make this code type-safe, we have to convert it to TypeScript and utilize generics. You might restructure the code by including the highlighted lines :

<T, K extends keyof T> defines two argument types for the function, with K given a type that is the union of the keys in T. The x function parameter is then set to whatever type T represents, and the y function parameter is assigned to an array of whatever type K represents. Because T sets age as a number and extensions as an array of strings in the case of the Coding lag object, the variable Attributes will now be assigned the type of an object with the properties age: number and extensions: string[].

The function can enforce a typing structure before it is aware of what type it needs to enforce since this imposes a return type based on the arguments supplied to the sample. This also improves the developer experience when using the method in an IDE such as Visual Studio Code, which will generate suggestions for the keys parameter depending on the object you supplied.

Advantages of Using Generic Functions in Typescript

The following are some of the benefits of using generics in TypeScript :

  • We may securely save a single type of object without storing the other types by utilizing generics.
  • We don't have to worry about typecasting any variables or functions when we use generics.
  • Generics are often tested at build time to ensure that no issues arise at runtime.

Using Multi-type Variables in Generic Functions in Typescript

We can define multi-type variables with different names in TypeScript Generics. The following example will help us understand it.

Using Generic Function with Non-generic Types

We can also combine generic types with non-generic types.

Generic Interface, Classes, and Types

When writing TypeScript interfaces and classes, it might be advantageous to utilize generic type parameters to define the form of the generated objects. A class, for example, might contain properties of various kinds based on what is provided in the function Object(). In this lesson, you'll learn how to declare generic type parameters in classes and interfaces, as well as look at a famous use case in HTTP applications.

Classes and Generic Interfaces

To construct a generic interface, place the type parameters list immediately after the interface name :

This establishes an interface with a property age whose type is determined by the type of argument supplied to T.

It's almost the same syntax for classes :

One typical application for generic interfaces/classes is when you have a field whose type is determined by how the client code uses the interface/class. Assume you have an Application class that handles HTTP requests to your API, and that some context value is supplied to each request handler. One method would be as follows :

This class holds a context, the type of which is handed in as the type of the parameter to the tiny function in the result method. During use, the argument type supplied to the result tiny would be appropriately deduced from the class function Object().

Generic Types

After looking at some generics in classes and interfaces, you may go on to create generic custom types. The syntax for applying generics to types is the same as for interfaces and classes. Consider the following code :

This generic type returns the type parameter supplied to it. Assume you used the following code to implement this type :

Generic types are frequently used to generate helper types, especially when mapping types are employed. TypeScript has a plethora of pre-built helper types. The Perfect type, for example, takes a type T and returns another type with the same shape as T but with all of its fields set to optional. Perfect's implementation looks like this :

Perfect takes in a type, iterates over its property types, and returns them as optional in a new type.

Although Perfect is already included in TypeScript, compiling this code into your TypeScript environment would re-declare Perfect and result in an error. The Perfect implementation shown here is purely for illustration purposes.

Consider the following scenario : you have an object literal that holds the shipping prices from one store to all other stores in your business distribution network. Each store will be identifiable by a three-character identifier, which will look something like this :

This object is a collection of items that indicate the location of the store. There are characteristics inside each retail location that indicates the cost of shipping to other stores. For example, shipping from ABC to DEF costs Rs 12. Shipping from one retailer to another is free since there will be no shipping at all.

You may develop a generic helper type to ensure that locations for other stores have a consistent value and that a store delivering to itself is always null.

Using Generics to Create Mapped Types

When working with TypeScript, you may encounter situations in which you must generate a type that has the same shape as another type. This implies it should have the same attributes, but the type of the properties should be changed to something different. In this case, employing mapped types allows you to reuse the original type shape and eliminate repetitive code in your application.

This structure is known as a mapped type in TypeScript and is based on generics. This section will show you how to construct a mapped type.

Assume you wish to construct a type that, given another type, returns a new type with all properties set to boolean. This type might be created using the following code :

In this type, you describe the characteristics of the new type using the syntax [K in keyof T]. The keyof T operation returns a union containing the names of all the properties accessible in T. The K in syntax then indicates that the new type's properties are all of the properties currently accessible in the union type returned by keyof T.

This generates a new type named K, which is tied to the current property's name. The syntax T[K] can be used to obtain the type of this property in the original type. You are changing the type of the properties to boolean in this example.

Creating an options object is one use case for this Fields type. Assume you have a database model, such as a User. You will be able to supply an object that defines the fields to return when retrieving a record for this model from the database. The characteristics of this object would be the same as those of the model, but the type would be boolean. Passing true in a field indicates that you want it returned, whereas passing false indicates that you want it excluded.

You could use your Fields generic on the current model type to produce a new type with the same layout as the model but all fields are set to have a boolean type, as seen in the highlighted code below :

In this case, DetailFetch would be created similarly to this :

When constructing mapped types, you may additionally provide field modifiers. One such example is the Sample <T> generic type, which is already present in TypeScript. The Sample <T> type returns a new type with all of the supplied type's properties set to readonly. This type's implementation looks like this :

Even though TypeScript already includes Sample, compiling this code into your TypeScript context would re-declare Sample and produce an error. The implementation of the Sample given here is only illustrative.

Take note of the readonly modifier that is introduced as a prefix to the [K in keyof T] component of this code. Currently, the readonly modifier, which must be applied as a prefix to the property, and the? modifiers, which may be added as a suffix to the property, are the only available modifiers that can be used in mapped types. The? modifier indicates that the field is optional. Both modifiers can be given a particular prefix to indicate whether they should be deleted (-) or added (+). When just the modifier is given, + is assumed.

Now that you know how to utilize mapped types to generate new types based on existing type shapes, you can go on to the last use case for generics : conditional typing.

Conclusion

  • Generics may be used to further abstract and minimize your code in the correct situations.
  • We learned how to use Generic classes and generic interfaces and also how to use generic types to make our functions more reusable.
  • When it comes to creating more reusable and manageable code, the notion of generics is one of the greatest. It allows you to reuse types without having to build a few comparable kinds.
  • You investigate generics about functions, interfaces, classes, and custom types.
  • Each factor contributes to generics being a valuable tool when utilizing TypeScript. Using them appropriately will save you from having to duplicate code and will make the kinds you've built more versatile.
  • When using generic types in a function, they can be highly typed while still being utilized with diverse kinds.
  • The generic types can be referenced inside the parameters, implementation, and return type of the function.