2

How do I append an item to an array of objects to a state (React) while using TS?

This is my code:

export type AppState = {
    tickets?: Ticket[],
}

export type Ticket = {
    id: string,
    title: string;
}

export type ApiC = {
    getTickets: (order:string, page:number) => Promise<Ticket[]>;
}

export class App extends React.PureComponent<{}, AppState> {

    state: AppState = {
    }


   fetchNewData = async () => {
        return await api.getTickets(this.state.currentOrder, this.state.page)
   }

    handleLoadMore = () => {

       let addData:Promise<Ticket[]> = this.fetchNewData()

        if (addData) 
            this.setState({
                tickets: [...this.state.tickets, addData]
            })
    }

I keep getting this error:

Type 'Ticket[] | undefined' is not an array type.

I tried:

let addData:Ticket[] = this.fetchNewData()

too and the error I get:

Type 'Promise<Ticket[]>' is missing the following properties from type 'Ticket[]': length, pop, push, concat, and 28 more. Type 'Ticket[] | undefined' is not an array type.

I tried writing it in all kind of variations with no luck.

Both pointing error in this line:

  > 144 |               tickets: [...this.state.tickets, addData]
        |                            ^
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
Imnotapotato
  • 5,308
  • 13
  • 80
  • 147
  • What do you want to happen if `this.state.tickets` *is* undefined? The compiler's telling you the correct thing: right now, your code doesn't work in that situation. – jonrsharpe Mar 06 '21 at 11:48
  • hmmm if it's undefined - so i want to populate it with new data fetched by the api request.. i guess. in which part of the process do i do that and how? @jonrsharpe – Imnotapotato Mar 06 '21 at 11:53
  • Well, where are you currently relying on it being an array? You need to make sure it *is* by then, or handle it not being. Should it *ever* really be undefined? Also you need to handle your promises correctly; as the compiler's telling you, you can't just unilaterally decide that a function return a promise of a value will return the value itself instead. – jonrsharpe Mar 06 '21 at 11:56
  • `if (this.state.tickets) {...}` ? im not sure i understand what you said about the promise thing @jonrsharpe – Imnotapotato Mar 06 '21 at 12:21

2 Answers2

2

There are few problems in your code, you can fix those:

  1. Remove the optional from state and initialize it with empty array
export type AppState = {
  tickets: Ticket[] // remove the ?
  // ...
}

constructor(props) {
  super(props)
  this.state = {
    tickets: [],
    // ...
  }
}
  1. Assuming addData is array of Ticket, you need to make handleLoadMore function async to use await on this.fetchNewData to get the data returned by it:
handleLoadMore = async () => {
  let addData = await this.fetchNewData()

  if (addData)
    this.setState({
      tickets: [...this.state.tickets, ...addData],
    })
    // Or
    this.setState({
      tickets: this.state.tickets.concat(addData),
    })
}
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • adding the async await worked, why do I need it here? (thanks for the answer) – Imnotapotato Mar 06 '21 at 12:33
  • 1
    I think `api.getTickets` uses `axios` and returns `Promise`, so you can drop async/await from there. I mean, you can remove `async` - `await` from `fetchNewData`. Try reading https://stackoverflow.com/q/49938266/2873538 – Ajeet Shah Mar 06 '21 at 12:41
0

You should destructure adddata as well.

tickets: [...this.state.tickets, ...addData]
Diwakar Singh
  • 684
  • 1
  • 5
  • 19