Reputation: 1786
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
Upvotes: 1
Views: 980
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
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
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