MisterniceGuy
MisterniceGuy

Reputation: 1786

How can I apply a Interface to a HTTP response

In my app I get a response from an API which has a response with the following pattern.

export interface IApiResponseBody<T = any> {
    Error?: string;
    Message?: string;
    RowsAffected?: number;
    Success?: boolean;
    Data?: T;
    RowCount?: number;
}

and I have no issue assigning the interface to the response which then lets me access the elements in response. Where I am having an issue is when I try to assign a interface to the Data via T like

let myData: IApiResponseBody<IPerson>  = {
    Success: true,
    Error: "",
    Message: "",
    RowsAffected: 9,
    Data: [{name: 'Steve', age: 26, gender : 'male'},
            {name: 'Susan', age: 21, gender : 'female'},
            {name: 'SteveFrank', age: 29, gender : 'male'}]}

I get an error no matter if I use an array in Data or a simple Doc.

TSError: ⨯ Unable to compile TypeScript: index.ts:9:5 - error TS2559: Type '{ name: string; age: number; gender: string; }[]' has no properties in common with type 'IPerson'.

9 Data: [{name: 'Steve', age: 26, gender : 'male'}, ~~~~

So how can I apply an interface to my Data element no matter if it's an array of docs or a simple doc.

Here is a link to the above code on Repl.it

Sample Playground

Upvotes: 1

Views: 980

Answers (3)

Md Rafee
Md Rafee

Reputation: 5530

Because, you want to access a data that might not exist. Because Data?: T[], is a shorthand of Data: T[] | undefined. It means that Data may contain a value of T[] or it may contain the value undefined.

So, when you call, myData.data[0].name it means, it may have the value steve or you want to call name property of first object of undefined data which is totally not acceptable, so the error trowed.

Solution 1:

you can check if the data is exist first, then print the object or property of object.

if (myData.Data) {
  console.log(myData.Data[0].name)
}

Solution 2

Or you can say there must be data, remove the ? character from interface.

export interface IApiResponseBody<T = any> {
  Error?: string;
  Message?: string;
  RowsAffected?: number;
  Success?: boolean;
  Data: T[];
  RowCount?: number;
}

Live solution: Repl.it

Upvotes: 0

Lia
Lia

Reputation: 11982

you can try:

export interface IApiResponseBody<T = any> {
    Error?: string;
    Message?: string;
    RowsAffected?: number;
    Success?: boolean;
    [key: string]?: T | T[];
    RowCount?: number;
}

and:

let myData: IApiResponseBody<IPerson>  = {
    Success: true,
    Error: "",
    Message: "",
    RowsAffected: 9,
    Data: [{name: 'Steve', age: 26, gender : 'male'}] // or {name: 'Steve', age: 26, gender : 'male'}
    }

Upvotes: 1

Brandon Taylor
Brandon Taylor

Reputation: 34553

Data? has to be an Array of type T, or if you want to allow an Array or a single Object, use a union.

export interface IApiResponseBody<T = any> {
  Error?: string;
  Message?: string;
  RowsAffected?: number;
  Success?: boolean;
  Data?: T | T[];
  RowCount?: number;
}

export interface IPerson {
  name?: string;
  gender?: string;
  age?: number;
}

Which now allows you to do:

let myData: IApiResponseBody<IPerson> = {
  Success: true,
  Error: "",
  Message: "",
  RowsAffected: 9,
  Data: [
    {name: 'Steve', age: 26, gender: 'male'},
    {name: 'Susan', age: 21, gender: 'female'},
    {name: 'SteveFrank', age: 29, gender: 'male'}
  ]
}

or:

let myData: IApiResponseBody<IPerson> = {
  Success: true,
  Error: "",
  Message: "",
  RowsAffected: 9,
  Data: {name: 'Steve', age: 26, gender: 'male'}
}

Upvotes: 0

Related Questions