Skip to content

ReturnType break the original funtion return type if function is method of a class #42706

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

Closed
linonetwo opened this issue Feb 9, 2021 · 6 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Needs More Info The issue still hasn't been fully clarified

Comments

@linonetwo
Copy link

linonetwo commented Feb 9, 2021

Bug Report

πŸ”Ž Search Terms

ReturnType method
ReturnType extends keyof

πŸ•— Version & Regression Information

"typescript": "4.1.3",

⏯ Playground Link

Playground Link

πŸ’» Code

// I think infer ReturnValue break the actual return type of each P

type AsyncifyProxy5<OriginalProxy> = {
  [P in keyof OriginalProxy]: OriginalProxy[P] extends (...arguments_: any) => infer ReturnValue
    ? (...arguments_: Parameters<OriginalProxy[P]>) => Promise<ReturnValue>
    : unknown;
};

/**
 * Bug is here:
 */


/**
const ggg: Promise<string | boolean | {
    a: 3;
    b: 4;
}>

But it should be just {
    a: 3;
    b: 4;
}
*/
const ggg = ({} as AsyncifyProxy5<IContextService>).get('environmentVersions');

πŸ™ Actual behavior

ReturnType gives Union of all ReturnType<OriginalProxy[P]>

πŸ™‚ Expected behavior

I hope it can give me the exact ReturnType for each method, so I can get async version of all class method.

@RyanCavanaugh RyanCavanaugh added the Needs More Info The issue still hasn't been fully clarified label Feb 11, 2021
@RyanCavanaugh
Copy link
Member

Please provide a repro that is both short and self-contained. We cannot investigate repros this large.

@RyanCavanaugh
Copy link
Member

Shortened

type Promisify<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : never;
type PromiseProxify<OriginalProxy> = {
  [P in keyof OriginalProxy]: Promisify<OriginalProxy[P]>;
};

interface IConstants {
  isDevelopment: boolean;
  platform: string;
  environmentVersions: { a: 3, b: 4 };
}
interface IContextService {
  get<K extends keyof IConstants>(key: K): IConstants[K];
}

declare const m: PromiseProxify<IContextService>;
const ggg = m.get("platform");

The type expression (...args: A) => Promise<R> : never isn't generic, so get isn't generic either. There are a few cases where we're able to synthetically make a function generic, but this definitely isn't one of them and it's not clear how to make that work in general.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Feb 12, 2021
@linonetwo
Copy link
Author

linonetwo commented Feb 13, 2021

Okay, should I keep this issue open? Will you reconsider this usage in the future?

I think I will manually as unknown as { a: 3, b: 4 } for now.

@RyanCavanaugh
Copy link
Member

I think this is pretty unlikely to change unless we collect new use cases around generic synthesis, or redo inference completely (oh no).

@saltman424
Copy link

For posterity, this is essentially a duplicate of #39594 and I have posted a use case and some proposals over there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

3 participants