I was hoping that giving a default value to a generic will take precedence over type inference, but it doesn't:
// placeholder for a real express response.send
const sendResponse = (x) => console.log(x);
function sendResult<T = never>(send: any, result: T) {
send(result);
}
// I want to use this always with a type
type Num = { x: number };
sendResult<Num>(sendResponse, { x: 1 });
sendResult<Num>(sendResponse, { x: 'sss' }); // correctly showing error
// When I don't supply type, I'd like an error.
// But, T gets inferred instead of defaulting to never... so, no error :-(
sendResult(sendResponse, {x: 1})
See demo
Is there a way to make sure an error is thrown if generic is not provided?
Typescript version: 3.5.2
Normally, when you call a generic procedure, you supply a type argument for each type parameter that the generic procedure defines. If you do not supply any type arguments, then the compiler attempts to infer the types to be passed to the type parameters.
Type Inference and Generic Methods. Generic Methods introduced you to type inference, which enables you to invoke a generic method as you would an ordinary method, without specifying a type between angle brackets.
Type argument inferred from the argument passed to parameter '<parametername1>' conflicts with the type argument inferred from the argument passed to parameter '<parametername2>'. A generic procedure is called without any type arguments, and the attempted type inference has produced a data type conflict among the type parameters.
Thus, in Java SE 7, you must specify the value of the value of the type argument as follows: This is no longer necessary in Java SE 8. The notion of what is a target type has been expanded to include method arguments, such as the argument to the method processStringList.
I don't understand the use case, since disabling behavior that TypeScript users expect is probably going to cause confusion. But you're the boss.
There is an existing GitHub suggestion at microsoft/TypeScript#14829 to allow a developer to indicate that a particular use of a generic type parameter should not be used for inference. There is no official support for this, but I think we can simulate it by taking advantage of the compiler's behavior when looking at conditional types that depend on an unresolved generic type parameter:
type NoInfer<T> = [T][T extends any ? 0 : never];
That is essentially a no-op on T
, since any value you plug in (say string
) will come out the other side: [string][string extends any ? 0 : never]
becomes [string][0]
becomes string
. But the compiler sees T extends any
and decides to defer the calculation until after T
gets resolved. In particular, it can't use the value to infer T
from that.
So then we can try
function sendResult<T = never>(send: any, result: NoInfer<T>) {
send(result);
}
And see how it behaves:
type Num = { x: number };
sendResult<Num>(sendResponse, { x: 1 }); // okay
sendResult<Num>(sendResponse, { x: "sss" }); // error
sendResult(sendResponse, { x: 1 }); // error
The first two cases work as you want because specifying Num
gives T
a definite value, and NoInfer<Num>
is just Num
. In the last case, the compiler really has no viable inference site for T
and thus it has to fall back to the default never
, and you get your desired error.
Playground link to code
So that works as you want, but remember that you might want to rethink this idea, since people who get that error might be confused about what the heck they're supposed to do to make the error go away. People rely on type inference, so you'll need some great documentation if you proceed with this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With