Ad

TypeScript Error: Cannot Invoke An Expression Whose Type Lacks A Call Signature

- 1 answer

I am trying to create a react reusable component: a table that should either be a list of Teams or a list of Games. Hence the GraphQL query is different based on what is fetched.

so I have those interfaces and types:

export interface Team {
  id: string;
  name: string;
}

export interface Game {
  id: string;
  competition: string;
}

export interface Data {
  allElems?: Team[] | Game[]
  [elements: string]: Team[] | Game[] | undefined
}

My component is like so :

interface SectionTableProps {
  query: object
}

class SectionTableQuery extends Query<Data, {}> {}

class SectionTable extends React.Component<SectionTableProps, {}> {
  constructor(props: SectionTableProps) {
    super(props);
  }
  render() {
    return (
          <SectionTableQuery query={this.props.query}>
          {({ data = {}, error, loading }) => {
            if (loading) {
              return <tbody><tr><td>LOADING</td></tr></tbody>
            };
            if (error !== undefined) {
              return <tbody><tr><td>ERROR</td></tr></tbody>
            };
            return (
              <tbody>
                {Object.keys(data).map(elements => {
                  data[elements].map(
                    elem => (
                    <tr key={elem.id} >
                      <th scope="row">{elem.id}</th>
                      {Object.keys(elem).map(k => {
                        if (k !== "id" && k !== "__typename") {
                          return <td key={elem[k]}>{elem[k]}</td>
                        }
                      })}
                    </tr>
                )
              )
            }
          )
          }
              </tbody>
            );
          }}
        </SectionTableQuery>
    )
  }
}

but I get the following error :

TypeScript error: Cannot invoke an expression whose type lacks a call signature. Type '(<U>(callbackfn: (value: Team, index: number, array: Team[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: Game, index: number, array: Game[]) => U, thisArg?: any) => U[])' has no compatible call signatures.  TS2349

    42 |               <tbody>
    43 |                 {Object.keys(data).map(elements => {
  > 44 |                   (data[elements] || []).map(
       |                   ^
    45 |                     elem => (
    46 |                     <tr key={elem.id}>
    47 |                       <th scope="row">{elem.id}</th>

why is that so ? I really don't know why Game and Team aren't compatible...

Ad

Answer

Just found a solution; don't know if it's the best though :

In my case I have to use declaration merging :

I can't write

export interface Team {
  id: string;
  name: string;
}

export interface Game {
  id: string;
  competition: string;
}

export interface Data {
  allElems?: Team[] | Game[]
  [elements: string]: Team[] | Game[] | undefined
}

as I'll get the error mentionned in my initial post. Instead, I have to declare my interfaces like so:

//team
interface Elem {
  id: string;
  name?: string;
  [attr: string]: string | number  | undefined
}

//game
interface Elem {
  id: string;
  homeTeamScore?: number
  competition?: string
  round?: string
}

export interface Data {
  elem?: Elem
  [elements: string]: Elem | undefined
}

At the most basic level, the merge mechanically joins the members of both declarations into a single interface with the same name.

Ad
source: stackoverflow.com
Ad