Skip to content

Consider making the value argument of promises optional. #1333

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
jespertheend opened this issue May 15, 2022 · 6 comments
Closed

Consider making the value argument of promises optional. #1333

jespertheend opened this issue May 15, 2022 · 6 comments

Comments

@jespertheend
Copy link

jespertheend commented May 15, 2022

I frequently pass in the promise callback argument into other functions that don't intend on providing any arguments in the callback function. For example:

async function doSomething() {
  // do something...
  await new Promise(r => setTimeout(r, 1000));
  // do something else...
}

admittedly this is a bit of a bad example, because setTimeout actually does provide an argument in its callback.
But consider the following:

function fireCallback(cb: () => void) {
    cb();
}

await new Promise(r => fireCallback(r));
//                                 ^^^------Argument of type '(value: unknown) => void'
//                                 is not assignable to parameter of type '() => void'.

playground link

Passing in r in fireCallback gives an error because the promise expects r to be called with a value, even though this is perfectly valid in JavaScript. The promise will simply resolve with undefined.

One way to work around this is by simply doing new Promise<void>(r => fireCallback(r)), but this isn't possible when working with JavaScript in strict mode. So the workaround ends up looking more like this:

/** @type {Promise<void>} */
const promise = new Promise(r => fireCb(r));
await promise;

playground link

which is really verbose and tedious to write.

The PromiseConstructor is currently defined as

new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;

making value: optional like so:

new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;

solves this issue, but I'm not sure if it might break anything else.

@MartinJohns
Copy link
Contributor

making value: optional like so:

T does not include undefined, and you call resolve without an argument, then you get an invalid value.

@yume-chan
Copy link
Contributor

  1. Promise is part of JavaScript, not DOM, so this is not the right issue tracker.
  2. the first argument of resolve is actually deliberately changed to be non-optional in TypeScript 4.1 (https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#resolves-parameters-are-no-longer-optional-in-promises) to prevent people from forgetting the argument.
  3. I think the type inference should be improved, when you write new Promise(r => setTimeout(r), 1000), the T in Promise should be whatever setTimeout will pass to it (or void if no argument given), if no better type can be inferred.

@jespertheend
Copy link
Author

Promise is part of JavaScript, not DOM, so this is not the right issue tracker.

Ah sorry about that, is the TypeScript repository the correct place for this?

@orta
Copy link
Contributor

orta commented Jun 4, 2022

It is, yes, but given the switch is pretty recent and release notes worthy (with some good arguments for why) I don't think the request is going to get too far.

@jespertheend
Copy link
Author

Yeah me neither, I'll mostly aim for point 3 in #1333 (comment)
My main issue is that

/** @type {Promise<void>} */
const promise = new Promise(r => fireCb(r));
await promise;

is tedious to type.

@jespertheend
Copy link
Author

I've submitted microsoft/TypeScript#49390

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants