Skip to content

[Bug] Union type compilation failed in Array.map() #29850

Closed

Description

@kuanyui

TypeScript Version: 3.3.3

Search Terms:
Array.map, union type
Code

// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.

interface fruit_t {
    name: string
    color: string
}

interface result_t {
    category: 'fruit' | 'vegetable' | 'animal'   // If you change this union type into `string`, it will pass the compilation.
    name: string
}

const fruits: fruit_t[] = [
    { name: 'Apple', color: 'red' },
    { name: 'Banana', color: 'yellow' },
    { name: 'Citrus', color: 'orange' },    
]

const results: result_t[] = fruits.map(x => ({ category: 'fruit', name: x.name }))
console.log(results)

Expected behavior:

Has no error.

Actual behavior:

  Type '{ category: string; name: string; }' is not assignable to type 'result_t'.
    Types of property 'category' are incompatible.
      Type 'string' is not assignable to type '"fruit" | "vegetable" | "animal"'.

17 const results: result_t[] = fruits.map(x => ({ category: 'fruit', name: x.name }))
         ~~~~~~~

Playground Link:

https://www.typescriptlang.org/play/index.html#src=interface%20fruit_t%20%7B%0D%0A%20%20%20%20name%3A%20string%0D%0A%20%20%20%20color%3A%20string%0D%0A%7D%0D%0A%0D%0Ainterface%20result_t%20%7B%0D%0A%20%20%20%20category%3A%20'fruit'%20%7C%20'vegetable'%20%7C%20'animal'%20%20%2F%2F%20If%20you%20change%20this%20union%20type%20into%20%60string%60%2C%20it%20will%20pass%20the%20compilation.%0D%0A%20%20%20%20name%3A%20string%0D%0A%7D%0D%0A%0D%0Aconst%20fruits%3A%20fruit_t%5B%5D%20%3D%20%5B%0D%0A%20%20%20%20%7B%20name%3A%20'Apple'%2C%20color%3A%20'red'%20%7D%2C%0D%0A%20%20%20%20%7B%20name%3A%20'Banana'%2C%20color%3A%20'yellow'%20%7D%2C%0D%0A%20%20%20%20%7B%20name%3A%20'Citrus'%2C%20color%3A%20'orange'%20%7D%2C%20%20%20%20%0D%0A%5D%0D%0A%0D%0Aconst%20results%3A%20result_t%5B%5D%20%3D%20fruits.map(x%20%3D%3E%20(%7B%20category%3A%20'fruit'%2C%20name%3A%20x.name%20%7D))%0D%0Aconsole.log(results)

Related Issues:

Activity

  1. azizhk commented on Feb 11, 2019

    @azizhk
    Contributor

    Maybe for a temporary workaround you can do

    const results: result_t[] = fruits.map(x => ({
      category: 'fruit' as 'fruit',
      name: x.name
    }))

    or

    const results: result_t[] = fruits.map(function(x): result_t  {
      return {
        category: 'fruit',
        name: x.name
      }
    })

    or

    const results: result_t[] = fruits.map(x => {
        const r: result_t = { category: 'fruit', name: x.name }
        return r
    })

    I would prefer using the 2nd and 3rd option as you don't use the as which is almost equivalent to overriding Typescript type inference.

  2. dragomirtitian commented on Feb 11, 2019

    @dragomirtitian
    Contributor

    It's not really a bug more of a design limitation. The arrow function is typed without any relation to the expected result, so there is no reason to keep the literal type 'fruit' it is widened to string. Then the map call is typed and the result is Array<{ category : string, name: string }> which is not assignable to results.

    Beside the options mentioned by Aziz Khambati (@azizhk), I would also mention the syntax to specify the return type of an arrow function which would be the most succint in this case I believe.:

    const results: result_t[] = fruits.map((x):result_t => ({ category: 'fruit', name: x.name }))
  3. ajafff commented on Feb 11, 2019

    @ajafff
    Contributor

    In the upcoming typescript@3.4 you can use the following to prevent widening:

    const results: result_t[] = fruits.map(x => ({ category: 'fruit', name: x.name } as const))
  4. jack-williams commented on Feb 11, 2019

    @jack-williams
    Collaborator

    This is fixed in 3.4 by #29478.

  5. ahejlsberg commented on Feb 11, 2019

    @ahejlsberg
    Member

    Duplicate of #11152. As Jack Williams (@jack-williams) says above, this is fixed in 3.4 by #29478 (and no need for as const in 3.4).

  6. 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

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions