Birthday Sale! Up to 40% off unlimited courses & creative assets Birthday Sale! Save up to 40%!
Lessons:14Length:1.2 hours
Typescript fundamentals 400x277
  • Overview
  • Transcript

2.6 Generics

Hi, and welcome back to TypeScript Fundamentals. In this lesson, I'm going to talk about Generics. To explain generics, I'm going to look at a simple function. I call it identity, and all it does is to return the input value again. For number, it returns a number. And for string, it should return a string, and so on. Unfortunately, the only way we can express that is by using the any type as an input and return type. This solution has two problems. We can't guarantee that the input type equals the output type. And the output type is no longer of the desired one. This is a great case for generics. They let you create constraints for your functions, but give you the freedom of using different types at the same time. Generic functions are defined using angle brackets, and something called type variables after the function name. This special variable that represents a type can then be used within the parameters, the return type and the function body. And just like that, you have a function that guarantees that the output type matches the input type. When you call the function, you have the option to use type interference to automatically guess the type of T for you. While this is very handy, I would personally recommend to explicitly add the type to the function most of the times to improve readability. You do that by using angle brackets again, but instead of T, you now pass in the real type. With generics, you can do much more, though. For instance, you can pass in multiple generic types, like in this transform function. Here, I'm going to transform a parameter from type T into type U. To fully accomplish that, I have to add a special constraint. For instance, I can tell that U extends T. And with that, TypeScript will recognize that there is a possible conversion from one type to another. When I call the function, TypeScript will verify that the two provided types are compatible, like string and null. If I swap out null with number, it raises an error. Of course, when using generics, you're limited to what properties or functions you can access on them. TypeScript knows nothing about the generic type until you further constrain it, like it does with the U type. Let's have a look at the generic length function. It wants to call length on the property, but that isn't defined. Luckily, I can easily, and in line, define an interface that has length and has a property or type number. I wouldn't recommend using this hack in your real code, but take the time and create an interface for it. Any type that implements a length property is now a valid type for this function, like a string. You can take the concept of generics further than just functions. Classes can be generic, too. When defining generic types for classes, you can use them everywhere within it, be it in properties, or functions and their bodies. This makes them very useful. Here in the example, I'm initializing a generic class that uses string, and call the identity function. It returns an array of strings, and the Y property on the class is also string. To recap, generics are a useful tool if you want to build reusable and flexible code. Type variables can be used in functions or whole classes. They are passed on when initializing a class, or executing a function, or are inferred from the input type if possible. Generics can also have constraints, like implementing a specific interface or extending a class. In the next lesson we are going to look at a widely used feature, called Decorators. See you there.

Back to the top