Generics in TypeScript

TypeScript

Let’s continue learning TypeScript. Today’s related to generics, a cool way of reusing components, because a major part of software engineering is building components that not only have well-defined and consistent APIs, but are also reusable.The main point is to create components that are capable of working on the data of today as well as the data of tomorrow will give you the most flexible capabilities for building up large software systems.

In languages like C# and Java, one of the main tools for creating reusable components is …

generics: to create a component that can work over a variety of types rather than a single one. This allows users to consume these components and use their own types.

Generics

Generics has the hability to define code templates that can be reused throughout your code base, giving you great functionality. As with interfaces, generics are only take into action when copiling, because it has no Javascript code associated. Generics also provide more flexibility when working with types, and it can be used in manu scenarios (in classes or functions).

One of the main uses of generics is minimizing the use of any type.

Let’s start off with the identity function, that is a function that will return back whatever is passed in. You can think of this in a similar way to the ‘echo’ command.

While using ‘any’ is certainly generic in that will accept any and all types for the type of ‘arg’, we actually are losing the information about what that type was when the function returns. If we passed in a number, the only information we have is that any type could be returned.

Instead, we need a way of capturing the type of the argument in such a way that we can also use it to denote what is being returned. Here, we will use a type variable, a special kind of variable that works on types rather than values.

function identity<T>(arg: T): T {
    return arg;
}

We’ve now added a type variable ‘T’ to the identity function. This ‘T‘ allows us to capture the type the user provides (for example, a number), so that we can use that information later. Here, we use ‘T’ again as the return type. On inspection, we can now see the same type is used for the argument and the return type. This allows us to traffic that type information in one side of the function and out the other.

We say that this version of the ‘identity’ function is generic, as it works over a range of types. Unlike using ‘any’, it’s also just as precise (ie, it doesn’t lose any information) as the first ‘identity’ function that used numbers for the argument and return type.

Once we’ve written the generic identity function, we can call it in one of two ways. The first way is to pass all of the arguments, including the type argument, to the function:

var output = identity<string>("myString");  // type of output will be 'string'

Here we explicitly set ‘T’ to be string as one of the arguments to the function call, denoted using the <> around the arguments rather than ().

The second way is also perhaps the most common. Here we use /type argument inference/, that is, we want the compiler to set the value of T for us automatically based on the type of the argument we pass in:

var output = identity("myString");  // type of output will be 'string'

Notice that we didn’t have explicitly pass the type in the angle brackets (<>), the compiler just looked at the value “myString”, and set T to its type. While type argument inference can be a helpful tool to keep code shorter and more readable, you may need to explicitly pass in the type arguments as we did in the previous example when the compiler fails to infer the type, as may happen in more complex examples.

Creating list by using generics

One of the uses of generics can be to create a class that simulate lists.


class ListOfNumbers {

_items: number[] = [];

add(item: number) { this._items.push(item);}

getItem(): number[] { return this._items; }</pre>
</div>
}

Now, imagine that you need a List of strings. Of course, the code is:


class ListOfStrings {

_items: string[] = [];

add(item: string) { this._items.push(item);}

getItem(): string[] { return this._items; }</pre>
}

If you compare both codes, the only diference is the type: in one is number and in other is string.With generics, you can create on class with generic type:


class Lists<T> {

_items: <T>[] = [];

add(item:<T>) { this._items.push(item);}

getItem(): <T>[] { return this._items; }</pre>

}

Now, you can use this code to create a type depending on the type you need, with only one definition!

For using the class, just remark the type you are using with the generic, and you’re done!

</div>
var miList = new Lists<number>();
var miListString = new Lists<string>();

As you may notice, you can use generics with functions, classes and interfaces.
That’s all by now!