Created
December 4, 2018 03:28
-
-
Save crutchcorn/25086b340e0269cf0108f4c5f43084db to your computer and use it in GitHub Desktop.
Typescript generics rough intro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// So, let's say you have a function that you want to accept any function type and return that type | |
// Don't worry about why right away, just | |
function returnSelf(a: any): any { | |
return a; | |
} | |
returnSelf(2); | |
returnSelf('t'); | |
const a = returnSelf('test').split(' '); | |
// The problem here is that with `any`, we're losing type info. We no longer know what the return value of `returnSelf` is | |
// How do we solve this? Type generics! | |
function returnSelfGeneric<T>(a: T): T { | |
return a; | |
} | |
returnSelfGeneric([123, 234]).map(() => {}); | |
// Is the same thing as: | |
returnSelfGeneric<number[]>([123, 234]).map(() => { }); | |
// The only reason we don't need the `<>` in the first example is because TS does a pretty good job at understanding what type you meant based on the args you're passing | |
// Ta-da! We're done. What we're saying here is that `a` should be any type. This type will be refered to as `T` from here on out. We can now use that same type | |
// elsewhere in the function definiton | |
// This is where you end up with things like `Promise<string>` comes into play. The defintion would look something like: | |
//Promise<T>((resolve: () => T, reject: () => any) => {then, catch});... You get the point, this is loose syntax and not valid | |
// What about multiple generics? | |
// Yup! | |
// We can restrict the TYPE of generic we want. This allows us to say that T can be any type so long as it extends on this object | |
function testGeneric<T extends {prop: number}, R>(arg1: T, arg2: R): T | R { | |
// Remember that comparisons can run on Dates and other stuff too | |
// What about something like this? We want a function that compares a prop but can have anything else? And `prop` should be a number? Seems complex, right? | |
if (arg1.prop > 2) { | |
return arg1; | |
} else { | |
return arg2; | |
} | |
} | |
// This is fine | |
testGeneric({ prop: 2, hello: 'hi' }, 23) | |
// This is not | |
testGeneric({ hello: 'hi' }, 23) | |
// You can even use type generics in other types | |
// & means that the type must have both. If T === {hello: string}, then AddType MUST have at least {prop: number, hello: string} | |
type AddType<T> = T & {prop: number}; // What does `&` do again? | |
// and finally with classes: | |
class GenericClass<T> { | |
prop: T; | |
constructor(arg1: T) { | |
this.prop = arg1; | |
} | |
method(): T { | |
return this.prop; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have expanded this Gist into a much better laid out and expanded post:
https://unicorn-utterances.com/posts/typescript-type-generics/