-
Notifications
You must be signed in to change notification settings - Fork 12.8k
ReturnType returns unknown if function's return type is generic argument of the function (with default value) that has not been set #57463
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
Comments
Duplicate of #48870. |
I do not think this is working as indented in sense that it might be an intentional side effect but it is frankly stupid to claim that this is "proper" behaviour that should be upheld. If this is working type ExtractDefault<T> = T extends infer U ? U : never;
type MyType<T = number> = T;
type DefaultType = ExtractDefault<MyType>; // number, NOT unknown I see no reason why it should not work with functions. |
That exhibits the same distinction as type Fun1<T = string> = () => T;
type Fun2 = <T = string>() => T; One is a generic type (i.e. a type-function) that resolves to a concrete, non-generic function type. The other is the type of a generic function, whose return type is not known until it’s called. Note that this is the same reason you can’t write |
I agree on the reasoning, but also that this is a silly way for the program to behave. What's really intended is an instantiation expression with an empty type arguments list, e.g.: // note: this gives an error:
// Type argument list cannot be empty.
type ShouldBeString = ReturnType< typeof func<> >; A workaround (that I hate) is to add a dummy variable, so you can create an instantiation expression: const func = <IGNORED, Return = string>(x:T): T =>{
throw new Error("implement me")
}
type F1 = typeof func<null>
type F2 = typeof func<null,string> |
@fatcerberus and what if I do this? type Fun2<T = string> = () => T;
type L = Fun2<number>; Do not get me wrong I understand that this is "how typescript was designed to work". But I do think that this distinguishment is frankly odd. If not removing this split competely, some expression that can be used to convert one to another might fix this issue? |
Is this what you're looking for? const func = <Return,>(): Return => {
throw new Error("implement me")
}
type Func<T=string,> = typeof func<T>
type ShouldBeNumber = ReturnType<Func<number>>; // number
// ^?
type ShouldBeString = ReturnType<Func>; // string
// ^? |
@cts-tradeit In case it's not clear, the reason for the distinction is: type Fun1<T = string> = () => T;
type Fun2 = <T = string>() => T;
let x: Fun1 = () => "foo"; // ok
let y: Fun1 = () => 42; // not ok, number is not assignable to string
let z: Fun2 = () => "foo"; // not ok, () => string can't function as a generic
let w: Fun2 = <T,>() => ({}) as T; // ok Without this distinction, you'd have no type you could use for |
@rotu No not exactly. Imagine using a package (which i cannot alter) that exports the function below. Why the singature looks like this? Who knows. The author chose it for some reason. Beyond this function there are 50 more that have similar generic gimmick. export const loadData = <Data = BasicData>(): Promise<Data> => {
// omitted
} Now, I need to know what type the function |
I think this might be close to what you need: #40179 |
From that signature, you can't know what If the author wants to communicate an actual type bound, it's with an export const loadData = <Data extends BasicData,>(): Promise<Data> => {
// omitted
} In this case, |
@fatcerberus If i understood the proposal correctly, it would allow me to do something like this: type Func = <T = string>(param: number) => T;
type FuncParams = Parameters<Func>;
type FuncReturn = ValueForArguments<Func, FuncParams>; // string |
@rotu what about adding something like this to the language? export const loadData = <Data = BasicData>(): Promise<Data> => {
// omitted
}
type R = ReturnType<typeof loadData<default>>; // BasicData I as the caller of the function know that I do not plan on specifying the generic argument any other than the default. It would be nice to be able to hint this to the language. U might argue that I may write the default type instead of |
I think I'd prefer if I do think it's ugly that type variables in generic functions can have defaults. I don't see a use for them versus |
If decisions we make either agree with you or are stupid, then I don't see much point in trying to engage with this issue. Seems like other folks have covered all the relevant points here - there are open issues on multiple possible avenues of solution for the particular problem. |
@RyanCavanaugh That is called false dichotomy. There are certainly more possibilities than these two. But honestly my hopes for this to be fixed were zero to resolved. However, it is good to raise awarness about shorcomings of the language. In few month, someone else will report this once again. |
🔎 Search Terms
ReturnType, generic, default
🕗 Version & Regression Information
⏯ Playground Link
No response
💻 Code
🙁 Actual behavior
ReturnType
returns unknown.🙂 Expected behavior
ReturnType
returns default type.Additional information about the issue
This was encountered when trying to write this kind of function:
The text was updated successfully, but these errors were encountered: