skip to Main Content

I get the message Property 'map' does not exist on type 'string | string[]'.:

const data = [
  ['1', ['11']],
  ['2', ['21']],
  ['3', ['31']],
]

data.map(topic => {
  topic[1].map(p => console.log(p))
})

What can I do to solve this (the error message, code works as expected)?

This is within an Astro project, JavaScript (no TypeScript), in case this is relevant.

enter image description here

3

Answers


  1. Why that happens?

    Typescript looks to the array ['1', ['11']] and infers the type as (string | string[])[]. .map exists in arrays but not in the string.

    To fix that:

    1. Tell TypeScript that this array is constant and will not be changed by adding as const at the end of the array.
    const data = [
      ['1', ['11']],
      ['2', ['21']],
      ['3', ['31']],
    ] as const
    
    data.map(topic => {
      topic[1].map(p => console.log(p))
    })
    
    1. When using the .map method check the type:
    const data = [
      ['1', ['11']],
      ['2', ['21']],
      ['3', ['31']],
    ]
    
    data.map(topic => {
      if (Array.isArray(topic[1]) {
        topic[1].map(p => console.log(p))
      }
    
      // OR
      if (typeof topic[1] === "string") {
         doSomething()
      } else {
        topic[1].map(p => console.log(p))
      }
    })
    
    Login or Signup to reply.
  2. data is inferred as (string | string[])[][] per default by the TypeScript compiler. That type is not specific enough to call an array method such as .map() on an item because for TypeScript any item in the data array could either be a string or a string[].

    What you’ll have to do is specifying the type of data in more detail. You can either do that with an Explicit Type Annotation

    const data: [string, string[]][] = [
      ["1", ["11"]],
      ["2", ["21"]],
      ["3", ["31"]]
    ];
    

    … or by using an const-assertion. That way TypeScript will use the narrowest possible type for your variable.

    const data = [
      ["1", ["11"]],
      ["2", ["21"]],
      ["3", ["31"]]
    ] as const;
    
    data.map(topic => {
      topic[1].map(p => console.log(p));
    });
    
    Login or Signup to reply.
  3. As the other answers already pointed out, if you can change the file to TypeScript, you can explicitly type data:

    const data: [string, string[]][] = [
      ["1", ["11"]],
      ["2", ["21"]],
      ["3", ["31"]]
    ];
    

    If you need your file to remain in JavaScript, you can still explicitly type data, by using JSDoc syntax, which is recognized by most IDEs.

    /**
     * @type {Array<[string, string[]]>}
     */
    const data = [
      ['1', ['11']],
      ['2', ['21']],
      ['3', ['31']],
    ]
    
    data.map(topic => {
      topic[1].map(p => console.log(p))
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search