Skip to content
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

resolve() of a promise accepts undefined when explicit generic type is specified #36749

Closed
soswow opened this issue Feb 12, 2020 · 6 comments · Fixed by #39817
Closed

resolve() of a promise accepts undefined when explicit generic type is specified #36749

soswow opened this issue Feb 12, 2020 · 6 comments · Fixed by #39817
Assignees
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@soswow
Copy link

soswow commented Feb 12, 2020

I am confused. It well can be the result of ECMAScript spec or something, but all this doesn't make sense to me.
TypeScript Version: 3.7.x-dev.201xxxxx
Search Terms: promise undefined and I looked through all of the 5 pages + looked through FAQ
Code:

type TypeA = {
  value: number;
}
const test = (): Promise<TypeA> => {
  return new Promise<TypeA>(resolve => {
    resolve(undefined); // Result of test() is Promise of TypeA. I return a promise that is resolved with  undefined and it's ok for some reason.
  });
};

const test2 = (): Promise<TypeA> => {
    return Promise.resolve(undefined);
};
test().then(typeAInstance => {
  // At this point here `typeAInstance` is of type TypeA and not! of `TypeA | undefined`
  console.log(typeAInstance.value.toFixed())
});

Expected behavior:
Both Functions should prevent me from doing writing stupid code at compile time.

Actual behavior:
Only second one does prevent me. First one allows runtime error to happened in the end.

Playground Link: http://www.typescriptlang.org/play/?ts=3.8.0-dev.20200211&ssl=1&ssc=1&pln=14&pc=4#code/C4TwDgpgBAKuEEEoF4oG8BQUoDcCGANgK4QBcUAdkQLYBGEATgNwYC+GAxgPYUDOwUYBH4ooACgCU5AAoMu1AJa8IAHjiQEAPhTbM2BhGBEGFShADuUWfKWr1iTWIO8uBHNGS6s2KM9fuxIgoAEwgAMwUKCGCJFmxWWLYWbj4BIX4AJlFJGTlFZTV4LR10b31DY1NrfIgAOj83CECQ8MjoxNYWdOBJWuAACwgKMVANAElUvAoODy9sFJcCOoIuAHMRoon+KZna-GI64C4AMQUAD2jJCTZYoA

Related Issues:

I don't understand where this undefined as one of the potential argument types is coming from:
Screen Shot 2020-02-12 at 7 38 11 PM

My lib.es5.d.ts contains this:

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

My lib.es2015.promise.d.ts contains this:

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

jcalz commented Feb 12, 2020

duplicate of #22040


I don't understand where this undefined as one of the potential argument types is coming from

It's an optional argument, and therefore accepts undefined.

@soswow
Copy link
Author

soswow commented Feb 12, 2020

@jcalz yeah, seems to be a duplicate. This is really a shame. I raised it because this caused an issue in production for me just now and I was really surprised TS can't handle such a simple case.
If resolve by default allows an optional argument, then all the .then callbacks should be also expected to be called with undefined regardless of the generic type defined.

@andrewbranch
Copy link
Member

This came up recently in our team chat and it was surprising to several of us. According to @rbuckton:

Because we (at the time) had no way to do new Promise<void>(resolve => resolve()). Now we do (because void parameters are optional), so we can probably tighten up that definition.

So I’m going to leave this open so we can revisit it.

@andrewbranch andrewbranch added the Needs Investigation This issue needs a team member to investigate its status. label Feb 13, 2020
@andrewbranch andrewbranch added this to the TypeScript 3.9.0 milestone Feb 13, 2020
@jcalz
Copy link
Contributor

jcalz commented Feb 13, 2020

crosslinking to #27522
will this run afoul of #29131 ?

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label May 20, 2020
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Jul 29, 2020
@mbroadst
Copy link

mbroadst commented Aug 13, 2020

Hi, I'm running into a similar problem with type specificity for a generic callback type in our code on the mongodb node driver. The current callback definition looks something like:

type Callback<T = any> = (error?: Error, result?: T) => void;

Our desire is to explicitly disallow undefined for the result type, and I was hoping this would do the trick:

type Callback<T = any> = (error: Error | undefined | void, result: T | void) => void;

Alas it seems undefined equates to void in this case, so the elision of the void parameter isn't necessarily specific to the Promise case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants