Generics

ref – https://www.typescriptlang.org/docs/handbook/2/generics.html
https://medium.com/ovrsea/checking-the-type-of-an-object-in-typescript-the-type-guards-24d98d9119b0
https://stackoverflow.com/questions/59183989/why-do-we-need-the-any-type-in-typescript

Concept

While using any is certainly generic in that it will cause the function to 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, let’s assume we have declared an interface called MyType:

In other words, it is to denote the type or interface we decide to use so that the compiler has the type information. That way, it does checking for us, and intellisense will bring up the attributes and methods of that type.

From the compiler’s view, it allows us to capture the type the user provides (e.g. number), so that we can use that information later. Here, we use the same MyType again as the return type. The compiler 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:

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

Notice that we didn’t have to explicitly pass the type in the angle brackets (<>); the compiler just looked at the value “myString”, and set Type 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.

When using any you’ll lose all type checking and safety checking that Typescript is offering, whereas, T behaves like a variable that will hold the Type that you don’t know what it is going to be

Explanation

The any type is an escape hatch—it allows you to effectively turn off Typescript’s type checking. Sometimes, there just isn’t a good way to tell Typescript what you are doing, so you use any to work around that.

And types are not necessarily any when you leave off a type annotation—in many cases, Typescript will infer a type, and then enforce that. let x = 2; will infer x as having type number. In intellisense, you’ll see type ‘any’, and when working with different types down the line, you won’t be able to see or access the object’s attributes and methods because we’re missing type information.

And you get type-safety and intellisense (depending on your editor) when you retrieve a value:

usages

say we use generics in class Test:

interface as generic

declare an object that conforms to our interface Person

output:

{
“name”: “ricky”,
“dob”: “June 6, 11980”
}

Class as generic

Create a class, then pass it into an instance of Test.

output:

MyData: {
“name”: “ricky”,
“dob”: “6680”
}

Generic Class extends Interface

Finally, let’s try extending generic classes. We make it so that our generic class can take any object type only if it conforms to interface Person.

This means that object must have properties name of type string, and dob of type string.

If we were to use MyData class, it would work because we do, after all, have name: string and dob: string.

Say we remove dob: string from MyData

We will get an error because our generic type T extends from Person. This means whatever class we choose to use, must conform to Person, which means we must implement name and dob of type string.

When we implemented class MyData to be passed in as the generic class, we have name of type string, but we are missing dob of type string.

Generic extend from Abstract

Say we declare a Base class

Then we use generic class and extend from abstract class.
This means any class we pass in to be used must satisfy abstract Base, which means to implement greetings().

Thus, let’s satisfy it by
1) extend from Base and use super

2) or simply implementing greetings() will work also.

Now, we can instantiate MyData and pass it into Test with no problem.

Generic class extends a concrete class

of course you don’t have to use ‘extend Base’. As you long as you implement it, its fine: