-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Specify whether generic is allowed to be infered as {} #15968
Comments
Are you suggesting that the generic be inferred as Default generics allow you to suggest something else to inferred: function convert<To = string, From = string>(from: From): To {
return from as any as To; // doesn't really matter
}
var x = convert(1); // To = string |
No, I mean to get a compiler error in such case. |
|
It is just a sample. |
Can you shed some light on the scenario. |
Only if all generic parameters can be deduced either manually or from parameters, the function is allowed to called. |
i understand. can you share a code sample where you feel you need this? |
Let's take this sample: class Base<T> { field: T; }
class Sub<T> extends Base<T> { constructor(public field: T) { super(); } }
function test<T1, A extends Base<T1>, T2>(arr: A, t2: T2) {
const data: Array<T1 | T2> = [];
data.push(arr.field);
data.push(t2);
return { input: arr, data };
}
const res = test(new Sub(1), "a"); // T1 = {} , A = Sub<number>, T2 = string
const first: number|string = res.data[0]; // error Nothing is wrong here and type inference is according to the rules. I want to have such functions to not compile and require writing explicit T1.. I don't want to talk about high-order kinds which solves the problem. |
Related to #14829 |
Here's a workaround, perhaps not to be taken too seriously (edited to work if T1 is set to a type variable in scope at the call site): const DUMMY = Symbol();
interface Do_not_mess_with_this_type_parameter {
[DUMMY]: never;
}
type IfDefinitelyNever<X, A, B, G extends Do_not_mess_with_this_type_parameter> =
("good" | G) extends {[P in keyof X]: "good"}[keyof X] ? B : ([X] extends [never] ? A : B);
class Base<T> { field: T; }
class Sub<T> extends Base<T> { constructor(public field: T) { super(); } }
interface T1_was_not_inferred_please_specify_it {
[DUMMY]: never;
}
function test<T1 = never, A extends Base<T1> = Base<T1>, T2 = never,
G extends Do_not_mess_with_this_type_parameter = never>(
arr: A & IfDefinitelyNever<T1, T1_was_not_inferred_please_specify_it, {}, G>, t2: T2) {
let arr_: A = arr;
const data: Array<T1 | T2> = [];
data.push(arr_.field);
data.push(t2);
return { input: arr_, data };
}
// error: Argument of type 'Sub<number>' is not assignable to parameter of type 'Sub<number> & T1_was_not_inferred_please_specify_it'.
const res = test(new Sub(1), "a");
const first: number|string = res.data[0]; I support the suggestion. I have another use case for it that I'll write up if I can think of a simple way to explain it. |
Here's another example (thanks @mattmccutchen for the answer there!). |
Setting the default to |
It's not that it doesn't cause an error, it's that the user facing error is not obvious. This is extremely debuggable:
This is much less so:
5k views on this question btw: https://stackoverflow.com/questions/53109837/how-to-make-a-generic-type-argument-required-in-typescript |
It is possible to use Consider this function: function myFunction<T = never, Input extends T = T>(input: Input): T { return input } This function requires
Demonstration: // TS-2345: Argument of type 'string' is not assignable to parameter of type 'never'
const value1 = myFunction('hello')
// TS-2345: Argument of type 'number' is not assignable to parameter of type 'string'.(2345)
const value2 = myFunction<string>(123)
// Passes fine!
const value3 = myFunction<string>('hello') This works because without a |
I would like to specify that 'To' is not allowed to be inferred as '{}'.
Perhaps some compilation flag, --noInferObjectFromGeneric, or something else.
The text was updated successfully, but these errors were encountered: