So to get started with our own generics here below loaded commented out code I will start with a generic
function you can build generic classes and functions all show both.
And here I'll start with a function.
Now let's say we want to have a function which basically merges two objects and returns a new object.
So here we could name it merge and we want to get object a an object B as a input.
Now of course we could write this function in a certain way we could say this is of type object and
this is of type object.
And then what does function does is it returns the result of object assign where it get object a and
object B.
So of course since we get this object assign method already built into normal javascript we could argue
if we really need a merge function.
But of course you could be doing additional work here.
You could enriched is with extra information with extra options and in the end does this just a demo
just an example.
So this would be valid we could call merge here and console log its result like this and then pass in
an object which has a name key and a second object which has a h.
And if we run that and we save this here in the browser indeed we get this outputs we get this merged
object.
Now this works the problem we have with that is if we try to store this merge name Max and age 30.
If we tried to store this year
I can't ex's name on the result.
I can't access age on the results on this merged object even though we know that both will exist because
typescript doesn't know this types we can't know this because we are just telling it you getting an
object that Indiana type infers that we return an object which is correct but which doesn't carry all
the information we could use here.
Now of course we can always do typecasting.
We can tell TypeScript and what we get back is an object where we have a name key and we have a H key
but that's really cumbersome if we have to do that.
So here generics can help us.
We turned it into a generic function by adding these angled brackets after the function name and then
we define Q identifiers.
Typically you start with T for type but you could use any identifier here doesn't have to be a single
character.
But the conventions use a single character and typically if you only have one generic type you named
as T.
And then you say well this generic type here this is now available inside of this function so we could
say what we get here is of type T look strange will get there no worries.
Now here we get two arguments where we don't know exactly what it will look like.
So I will accept a second generic type here simply by adding a comma and the angle brackets and then
we just continue in the alphabet and Deford a second generic parameter or type you might be using in
a function typically is named you.
So we could say this is of type you know what test is yield us.
Well a lot actually as you see with this alone if you hover over emerge typescript infers that this
function returns the intersection of T and you could of course also set is explicitly like this but
we don't even need to do that because object assign returns an intersection and therefore since we returned
a result of object assigned types could automatically understands that this function returns the intersection.
So how is this helpful then.
Well if we now hover over merged object we see that now with this alone typescript understands that
what we store in merged object is the intersection of these two object types because it sees that we're
passing in these objects which are of these object types.
It infers name string and h no and that our function returns the intersection.
Why is it able to inferred is now and not with object which we had before because object is a highly
unspecific type we say any object and yes therefore typescript is able to infer that we return the intersection
of object and object but the intersection of two unknown objects is just a new unknown object which
doesn't offer any additional type information to typescript with generic types.
What we're telling typescript is that these two parameters can and often will be of different types
and Danforth type good is able to understand dead we're not just working with some random objects type
but dead we will get different type data here and the dysfunction overall will return the intersection
of debt data and Danforth type good is able to understand that what we store in here in merged object
is such intersect that data of these two inputs because now we're not just dealing with some unknown
objects here but with very specific types and therefore for now if a console log merged object age here
this works without errors as you can tell here I'm printing thirty because of generic types we're giving
time of the extra information that we don't know what exactly the types will be short they will be objects
here we can tell that but we don't know if it's an object with a name key with the H key with a Hobbes
key we don't know and we don't care we don't care about the exact object here we don't want to specify
that this has to be of this type because then all of a sudden if I had Hobbes in there we would have
a problem.
So I don't want to be that restrictive I just want to say this is of any type which I don't care about
but it's most likely a different type than this one here.
And if it would be the same that would be fine too but typescript understands that we do have specific
types here for these two parameters and then we returned intersection of them instead of just having
any unspecific object here.
Now specifically the magic here is not just that we tell typescript that we got two different types
here but dead these types are not set in stone when we define this function but they are set dynamically
when we called the function.
So here we're calling the function and types in first the types for two arguments for t it basically
fills in an object type with an object with a name property which holds a string and a Hobbes property
which holds an array of strings and for a you add fields in a type of type object with H property where
h is of type No.
Now when we call this function again in number line and we pass in different objects in a store does
in a new constant with a new name then of course different types are filled in for t and you for this
function call.
You can also specifically tell types which types it should fill in by adding angle brackets after the
function name when you call it and then you would fill in your own types for t and you we could tell
typescript a t should be of type String for this function call and you should be of type No.
But then of course typescript would complain about the concrete values were passing in here because
this clearly is not a string.
And if we would fix this this clearly would not be of type.
No.
So here we could be very specific and say well the first argument were the type t to be precise for
this function call here will be an object type where we have a name property which is of type String
and a Hobbes property which is of type String array and the concrete type for you for this function
call will be an object where we have a property which should be of type no.
And now we would be good and no errors would be there anymore and this would work.
But this is redundant.
You can absolutely do that and it is important to understand that this is in the end what generics are
all about that you can fill in different concrete types for different function calls but we don't need
to do that here because typescript simply infers the types of the values we're passing as arguments
here and then add plaques in the inferred types for t and you for this function call.
That's how generics work behind the scenes in the end.