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

Unable to narrow Promise return types #43378

Closed
andparsons opened this issue Mar 25, 2021 · 3 comments
Closed

Unable to narrow Promise return types #43378

andparsons opened this issue Mar 25, 2021 · 3 comments

Comments

@andparsons
Copy link

andparsons commented Mar 25, 2021

Bug Report

I am expecting to get a compiler error when the return type of a promise does not match exactly.

Currently the wrapping of a type in a Promise changes the behaviour of the type narrowing, instead allowing for additional properties to be declared outside the defined type.

🔎 Search Terms

promise, return-type, type-narrowing

🕗 Version & Regression Information

4.2.3

⏯ Playground Link

Playground link with relevant code

💻 Code

For a normal object, I can get the compiler error as expected with the following:

interface SingleProperty {
  aSingleProperty: string
}
const willErrorAsExpected: SingleProperty = {
  aSingleProperty: "aString",
  anAdditionalPropertyThatShouldCauseAnError: "aString",
}

When working with a Promise, it seems that additional properties on the type are allowed, even though the compiler will error as expected if the return does NOT include all required properties in the type.

interface SingleProperty {
  aSingleProperty: string
}
const willNotErrorAsExpected: Promise<SingleProperty> = new Promise<void>((resolve) => {
  setTimeout(() => {
    resolve()
  }, 1)
}).then(() => {
  return {
    aSingleProperty: "aString",
    anAdditionalPropertyThatShouldCauseAnError: "aString",
  }
})

const willErrorAsExpected: Promise<SingleProperty> = new Promise<void>((resolve) => {
  setTimeout(() => {
    resolve()
  }, 1)
}).then(() => {
  return {
    theWrongProperty: "aString",
  }
})

🙁 Actual behavior

The willNotErrorAsExpected const should trigger a compiler error when a property that is additional to it's promised return type, but does not

🙂 Expected behavior

When explicitly specifying the promise return type, the behaviour should match that of a non-promise in the way the type narrows what is allowed.

@MartinJohns
Copy link
Contributor

Extra properties are legal in TypeScript. Check the "structural typing" section in the FAQ.

@MartinJohns
Copy link
Contributor

MartinJohns commented Mar 25, 2021

To expand on this: The excess property check only works for object literals whose target type is known. This is not the case for your willNotErrorAsExpected example. Here the anonymous function passed to then has an inferred return type consisting of two properties. Then the resulting Promise<> type with those properties is assigned to your Promise<SingleProperty>, and the assignability check assures that this is alright (as additional properties are fine).

You can fix this by providing an explicit type annotation to your function:

const willNotErrorAsExpected: Promise<SingleProperty> = new Promise<void>((resolve) => {
  setTimeout(() => {
    resolve()
  }, 1)
}).then((): SingleProperty => {
  return {
    aSingleProperty: "aString",
    anAdditionalPropertyThatShouldCauseAnError: "aString",
  }
})

This is basically the same issue as #43365 and many others.

@andparsons
Copy link
Author

My mistake, I thought this was an issue with promises, and it's just me lacking understanding how general function returns work in this way.

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

2 participants