最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Typescript type issue in map function of mixed types react - Stack Overflow

programmeradmin1浏览0评论

I have defined two types, Team and Position. They are both part of an array that I iterate over in my react ponent.

based on the types defined below in my map function I am seeing the following error.

Examples of errors I am seeing.

Property 'name' does not exist on type 'Position'. [2339]

Property 'position' does not exist on type 'Team'. [2339]

Is it not possible to check that the array contains either type?

My code looks like as follows:

type Team = {
   name: string; 
   city: string;
} 

type Position = {
   position: number;
}

const Component = () => {
    const teamsAndPosition = [
       {
        name: 'Arsenal', 
        city: 'London',
       },
      {
        name: 'Everton', 
        city: 'Liverpool',
       },
      { 
         position: 2
      }
    ];

    const [list, setList] = useState<Array<Team | Position >>(teams)
    
    list.map((item: Team | Position) => {
       return item.name ? (
         <div>
           // I am seeing an error for these below
           <p>{item.name}</p>
           <p>{item.city}</p>
         </div>
       ) : (
         <p>{item.position}</p>
       )
    })
}    

I have defined two types, Team and Position. They are both part of an array that I iterate over in my react ponent.

based on the types defined below in my map function I am seeing the following error.

Examples of errors I am seeing.

Property 'name' does not exist on type 'Position'. [2339]

Property 'position' does not exist on type 'Team'. [2339]

Is it not possible to check that the array contains either type?

My code looks like as follows:

type Team = {
   name: string; 
   city: string;
} 

type Position = {
   position: number;
}

const Component = () => {
    const teamsAndPosition = [
       {
        name: 'Arsenal', 
        city: 'London',
       },
      {
        name: 'Everton', 
        city: 'Liverpool',
       },
      { 
         position: 2
      }
    ];

    const [list, setList] = useState<Array<Team | Position >>(teams)
    
    list.map((item: Team | Position) => {
       return item.name ? (
         <div>
           // I am seeing an error for these below
           <p>{item.name}</p>
           <p>{item.city}</p>
         </div>
       ) : (
         <p>{item.position}</p>
       )
    })
}    
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jan 25, 2019 at 16:36 peter flanaganpeter flanagan 9,85027 gold badges82 silver badges140 bronze badges 7
  • 2 well if item can be Team or Position should you show the item.name and item.position alternatively, depding of the type of item? – Titian Cernicova-Dragomir Commented Jan 25, 2019 at 16:39
  • it is a bit more plicated than what I have posted here. I have dumbed down the example here for the question. Hopefully it still makes sense :-D. Basically I show a different element/ponent based on the object passed in. but the array can contain either our. Blame the designers :-) – peter flanagan Commented Jan 25, 2019 at 16:40
  • In both cases, you face a scenario, where property does not exist. You may want to extend your types with ? optional property, or do a {item.name ? item.name : ''} – Shevchenko Viktor Commented Jan 25, 2019 at 16:44
  • @TitianCernicova-Dragomir has a good working solution for you. Alternately, if you have the option to change some things around, you could consider making both Team and Position members of a parent class and then call the properties canonically so that there are no requests that can't be fulfilled. Still, I would add checks to make sure properties are available before trying to access them, else you will run the risk of errors whenever data is inplete. – J E Carter II Commented Jan 25, 2019 at 16:54
  • hmmm, obviously I appreciate the help, but I am not sure I really like either of these solutions. The array will always contain one. I will update the question with the array included. – peter flanagan Commented Jan 25, 2019 at 16:57
 |  Show 2 more ments

1 Answer 1

Reset to default 5

When dealing with a variable that might be one of two (or more) types you can check that a unique property on the object exists before dealing with the object so typescript can deduce what type it is.

Example:

interface IObjectYo {
  someProp: number
  same: boolean
}

interface IDifObjYo {
  otherProp: number
  same: boolean
}

function example(someArg: IObjectYo | IDifObjYo) {
  console.log(someArg.someProp) // tsc plains because someProp doesn't belong to IDifObjYo
  if ('someProp' in someArg) {
    console.log(someArg.someProp) // tsc knows it must be type IObjectYo because someProp only belongs to IObjectYo
  } else {
    console.log(someArg.otherProp) // tsc knows this is IDifObjYo because the first condition failed (which means it must be of type IDifObjYo)
  }
  if ('same' in someArg) {
    console.log(someArg.someProp) // make sure the property is indeed unique between the possible types or tsc can't infer
  }
}

In your case (and I'm not a React guy) you could do something like this:

type Team = {
   name: string;
   city: string
} 

type Position = {
   position: number;
}

const Component = () => {
    const [list, setList] = useState<Array<Team | Position >>(teams)

    list.map((item: Team | Position) => {
       return 'name' in item ? (
          <div>
             <p>{item.name}</p>
             <p>{item.city}</p>
          </div>
       ) : (
        <p>{item.position}</p>
       )
    })
}    
发布评论

评论列表(0)

  1. 暂无评论