Skip to content

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

Closed

Description

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.

Activity

  1. ahejlsberg commented on Feb 10, 2019

    @ahejlsberg
    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.

  2. ahejlsberg commented on Feb 10, 2019

    @ahejlsberg
    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.

  3. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions