Modify a Generic Type Default for Improved Error Messages
This solution doesn't involve any complex conditional types, or odd mapping. All it requires is a basic understanding of how type arguments work in TypeScript.
When you don't pass a type argument, it gets inferred as
This means that
fetchData without a type argument returns a `Promise
0:00 The solution here is probably simpler than you expect. It doesn't involve any crazy conditional types. It doesn't involve any weird mapping. It just involves a little bit of understanding of how type arguments work in TypeScript.
0:13 When you don't pass a type argument, how does it get inferred? It gets inferred as unknown. Now fetchData, when you don't pass in a type argument, basically returns a promise with unknown, which is how this ends up as data unknown. If we remove the await, this would be Promise unknown.
0:34 How do we make it so the unknown is never available? We change the default of TResult and we say TResult equals "You must pass a type argument to fetchData." Now this data is technically typed as any and actually, it's any inside here too, and we end up with Promise TResult.
0:57 What you get is now data is "You must pass a type argument to fetchData," when there's no type argument specified, and data up here is name string. This is really neat actually. What it does is it allows the user to understand what's going wrong, and as soon as we pass a type argument to it, then we say whatever string, then you're good to go.
1:22 Now one thing that's interesting here is that you then can't really constrain TResult. You can't say if you're sure that it always has a data attribute or like a data any for instance, then this wouldn't match that constraint. If TResult has to be of a certain shape, then this doesn't work.
1:43 For unconstrained generics, if you want the user to pass a type argument there, then this is actually a really neat little solution. Well done if you found the solution. Good stuff.