Skip to content

Type string not assignable to specific string inside Promise.then return value #29815

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
cdimitroulas opened this issue Feb 7, 2019 · 2 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@cdimitroulas
Copy link

cdimitroulas commented Feb 7, 2019

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms:
"typeof string is not assignable to"
"promise"

Code

interface ITest {
  name: 'test'
}

const createTestAsync = (): Promise<ITest> => Promise.resolve().then(() => ({ name: 'test' }))
// The same works if you write:
//    const createTestAsync = (): Promise<ITest> => Promise.resolve({ name: 'test' })

const createTest = (): ITest => {
  return { name: 'test' }
}

Expected behavior:
Expect both sync and async functions (createTest and createTestAsync) to compile without errors

Actual behavior:
createTestAsync throws the following compilation error:

Type 'Promise<{ name: string; }>' is not assignable to type 'Promise<ITest>'.
  Type '{ name: string; }' is not assignable to type 'ITest'.
    Types of property 'name' are incompatible.
      Type 'string' is not assignable to type '"test"'.

Playground Link:
https://www.typescriptlang.org/play/#src=interface%20ITest%20%7B%0D%0A%20%20name%3A%20'test'%0D%0A%7D%0D%0A%0D%0Aconst%20createTestAsync%20%3D%20()%3A%20Promise%3CITest%3E%20%3D%3E%0D%0A%20%20Promise.resolve().then(()%20%3D%3E%20(%7B%20name%3A%20'test'%20%7D))%0D%0A%0D%0Aconst%20createTest%20%3D%20()%3A%20ITest%20%3D%3E%20%7B%0D%0A%20%20return%20%7B%20name%3A%20'test'%20%7D%0D%0A%7D%0D%0A

Related Issues:
#29078

Further notes
Hi there, first time I'm interacting with the Typescript github repo. I wasn't able to find any issues which described the exact same problem but I wasn't sure exactly what search terms to use so apologies if there are duplicates. Furthermore, I am wondering whether there is something inherent in how Promises work which makes this problem occur - if so, I would love to be educated on the matter! :)
If there is any other information I can provide, please let me know.

@ahejlsberg ahejlsberg self-assigned this Feb 10, 2019
@ahejlsberg ahejlsberg added the Bug A bug in TypeScript label Feb 10, 2019
@ahejlsberg ahejlsberg added this to the TypeScript 3.4.0 milestone Feb 10, 2019
@ahejlsberg
Copy link
Member

This is related to type inference where the target is a union of type variables.

interface Promise<T> {
    then<TResult1 = T, TResult2 = never>(
        onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
        onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
    ): Promise<TResult1 | TResult2>;
    // ...
}

For reasons that are lost to history we don't make inferences to type parameters in unions with other type parameters. I think it was because we previously lacked the ability to assign lower priority to such inferences (as they are more speculative), but we have that ability now. So, when inferring from Promise<XXX> to Promise<T | U> we ought to make a lower priority inference of XXX to both T and U. Doing so would solve your issue. I will look at making this change.

@ahejlsberg
Copy link
Member

For example, we currently get this wrong:

declare function test<T, U>(x: T | U): T | U;
let s: string = test('a');  // Error: Type '{}' is not assignable to type 'string'

We ought to infer "a" for both T and U.

@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Feb 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

2 participants