Description
I'm sure there an issue or discussion about this I missed, but I couldn't find it via search.
Search Terms
Generic, infer, default, {}, { }, empty, shape, object
Suggestion
Behind a new strict
mode flag --strictGenericBindings
, when binding concrete types to generic type parameters, if a type can't be inferred TSC should throw an error at compile time instead of defaulting to {}
.
Use Cases
Let's say you have the following Promise:
const p = new Promise(resolve => resolve(42)) // Promise<{}>
p.then(r =>
r + 4 // Error: Operator '+' cannot be applied to types '{}' and '4'.
)
This gives an error when you try to use the Promise's result. This experience isn't ideal, because the error is non-local. Looking at the code that threw that error, it's not obvious why r
is {}
.
If I try to fix this by adding an explicit annotate when I consume r
, it works:
p.then((r: number) => {
r + 4 // OK
})
But if I have strictFunctionTypes
enabled, that breaks because {}
isn't assignable to number
:
p.then((r: number) => {
r + 4 // Error: Argument of type '(r: number) => void' is not assignable to parameter of type '(value: {}) => void | PromiseLike<void>'.
})
The real fix is to explicitly bind a type parameter when I consume Promise
:
const p = new Promise<number>(resolve => resolve(42))
p.then(r => {
r + 4
})
But unfortunately, the error messages didn't help me get there.
A possible solution to this problem is to throw a helpful error message when a generic type parameter can't be inferred. This can help prevent bugs, and help programmers catch bugs earlier:
const p = new Promise(resolve => resolve(42)) // Error: Unable to infer a generic type for Promise<T> - please bind one explicitly. Eg. new Promise<myType>(...).
p.then(r => {
r + 4
})
Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript / JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. new expression-level syntax)