Data type error when fetching data from backend - angular13

Angular is throwing the following error:
"Type 'Object' is missing the following properties from type 'never[]': length, pop, push, concat, and 28 more.
this.movies = data;"
// movie-list.component.ts
// ...
export class MovieListComponent implements OnInit {
movies = [];
constructor(
private apiService: ApiService) { }
ngOnInit() {
this.apiService.getMovies().subscribe(
data => {
this.movies = data;
})}
}
I´ve changed the "movie" variable for
movies: any[] = [];
but the error still appears
// api.service.ts
// ...
export class ApiService {
baseUrl = 'http://127.0.0.1:8000/api/movies/'
headers = new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'token 61a1e3bfcfaea4fceee08d52fa132c788204d5e4'
})
constructor(
private http: HttpClient
) {}
getMovies() {
return this.http.get(this.baseUrl, {headers: this.headers});
}
}
console.log(data)
(3) [{…}, {…}, {…}]
0: {id: 1, title: 'Titanic', description: 'Romantic movie '}
1: {id: 2, title: 'Avatar', description: 'SiFy movie'}
2: {id: 4, title: 'Dune', description: 'SiFy movie'}
length: 3
[[Prototype]]: Array(0)

My app was missing a movie.ts file:
export interface Movie {
id?: any;
title?: string;
description?: string;
}
so I had to refactor the getMovie method in the following way:
getMovies(): Observable<Movie[]>{
return this.http.get<Movie[]>(this.baseUrl, {headers: this.headers});
}

Related

How to define typescript interface for array on objects

Here is the data from the server.
I want to display it with map on UI.
Here is the interface I did -
export interface IHistory {
reports: Readonly<{
readonly id?: string,
status?: Status,
readonly created_at?: Date,
}>
}[];
The map I'm doing:
{props.history!.map((index, idx) => {}
The error:
TypeError: Cannot read properties of null (reading 'map')
What am I doing wrong?
I want to display only the reports.
Added -
Interface -
export interface IHistory {
reports: Array<{
id?: string;
status?: Status;
created_at?: string;
}>;
};
const [ hitoryState, setHistoryState ] = useState<IHistory | null>(null);
useEffect(() => {
backendAPIAxios.get('/history')
.then((response: AxiosResponse<IHistoryResponse>) => {
if (!response.data) {
return alert('Failed to get history');
}
setHistoryState(() => response.data);
})
.catch((e: AxiosError) => {
// alert(`Failed to get history with error: ${e}`);
});
}, [setHistoryState])
console.log(props.history!.reports.map((hist) => <p>{hist.created_at}</p>))
This is the error I'm getting:
You are making IHistory an array of reports objects, when reports is the field with the array. Also, created_at will likely be a string and not a date if it's being returned from the backend.
type Status = "fair" | "unfair";
interface IHistory {
reports: Array<{
id?: string;
status?: Status;
created_at?: string;
}>;
};
const backendHistory: IHistory = {
reports: [
{ id: "123", status: "fair", created_at: new Date().toISOString() },
{ id: "456", status: "unfair", created_at: new Date().toISOString() },
]
};
const result = backendHistory.reports.map(({ id }, _idx) => id);
console.log("result", result);
React code:
import React from "react";
type Status = "fair" | "unfair";
interface IHistory {
reports: Array<{
id?: string;
status?: Status;
created_at?: string;
}>;
}
async function fakeFetch(): Promise<IHistory> {
const backendHistory: IHistory = {
reports: [
{ id: "123", status: "fair", created_at: new Date().toISOString() },
{ id: "456", status: "unfair", created_at: new Date().toISOString() }
]
};
return new Promise((resolve) =>
setTimeout(() => resolve(backendHistory), 1000)
);
}
export default function App() {
const [backendHistory, setBackendHistory] = React.useState<IHistory>();
React.useEffect(() => {
let isAlive = true;
(async function () {
const result = await fakeFetch();
if (isAlive) {
setBackendHistory(result);
}
})();
return () => {
isAlive = false;
};
}, []);
return (
<div className="App">
<h1>Backend History</h1>
{backendHistory ? (
backendHistory.reports.map((hist) => <p>{hist.id}</p>)
) : (
<span>loading</span>
)}
</div>
);
}

Type '{ userId: string; }' has no properties in common with type 'AxiosRequestConfig'. | Axios - Next.js with typescript

( Hi comunnity ) I have this piece of code, everything was working fine, but got an error once i create the API.delete function, don't know what is going on there actually
import axios, { AxiosRequestConfig } from "axios";
const API = axios.create({ baseURL: "http://localhost:5000/api" });
// Set header for each request to give permission
API.interceptors.request.use((req: AxiosRequestConfig) => {
if (localStorage.getItem("Auth")) {
req.headers.Authorization = `Bearer ${
JSON.parse(localStorage.getItem("Auth")).token
}`;
}
return req;
});
// login - register - update perfil
export const login = (loginData: {
email: string | null;
password: string | null;
}) => API.post(`/user/login`, loginData);
export const register = (registerData: {
email: string;
password: string;
name: string;
}) => API.post("/user/register", registerData);
export const updatePerfilPhotos = (
photosBase64: { perfil?: string; banner?: string },
id: string
) => API.patch(`/user/update/${id}`, photosBase64);
export const AddNotification = (
userInformation: { userId: string },
id: string
) => API.patch(`/user/notification/${id}`, userInformation);
export const DeleteNotificationOrFriend = (
userInformation: { userId: string },
id: string
) => API.delete(`/user/deleteNotification/${id}`, userInformation);
//
In the API.delete function there's a problem :
(parameter) userInformation: {
userId: string;
}
Type '{ userId: string; }' has no properties in common with type 'AxiosRequestConfig'
What does that mean ? why is that happening, how can i fix this ?
Thanks for your time friends !
I think the delete method signature should be like this,
API.delete(`/user/deleteNotification/${id}`, { data: userInformation })
Refer: https://github.com/axios/axios/issues/897#issuecomment-343715381

How would i define my interface for this JSON data coming from action?

How would i define my interface for this JSON if i want to access the data present in the data object here:
items:
data: Array(1)
0: {reactionType: Array(1), _id: "5d46f4cd5f68325378603144", name: "ravi", email: "nischals#ravi.com", phone: 12345678, …}
}
length: 5
status: 200
statusText: "OK"
im doing like this:
name: String;
}
export interface items {
items: {
data: Array<Object>;
};
}
export interface SettingCategoryAddItemProps {
addItem: Function;
getItem: Function;
items: items;
}
But doesnot work
try used this
export interface data {
reactionType:any[],
_id:string,
name:string,
email:string,
phone:string,
...
}
export interface items {
items:{
data:data[],
}
}
export interface SettingCategoryAddItemProps {
addItem: (item:any)=>{if want to show any thing as conforme or not};
getItem: (itemname:string)=>{item };
items: items;
}
It is common practice to prefix an interface name with I in typescript. From your JSON I can do this:
export interface IData {
reactionType: any[]; // Better create a type for any
_id: string;
name: string;
email: string;
phone: string;
....
}
export interface IItems {
items: {
data: IData[],
}
}
export interface ISettingCategoryAddItemProps {
addItem: (item: any) => void; // Better create a type for any
getItem: (itemId: string) => object; // // Better create a type for Object
items: IItems;
}

Argument of type '{ status: string; DetailsAnnouncementListItemState: { items: IListItem[]; columns: undefined

I have the following error, and below I will try to explain what I am trying to accomplish:
[ts]
Argument of type '{ status: string; DetailsAnnouncementListItemState: { items: IListItem[]; columns: undefined[]; }...' is not assignable to parameter of type 'Pick<IFactoryMethodState, "status" | "DetailsAnnouncementListItemState">'.
Types of property 'DetailsAnnouncementListItemState' are incompatible.
Type '{ items: IListItem[]; columns: undefined[]; }' is not assignable to type 'IDetailsAnnouncementListItemState'.
Types of property 'items' are incompatible.
Type 'IListItem[]' is not assignable to type 'IAnnouncementListItem[]'.
Type 'IListItem' is not assignable to type 'IAnnouncementListItem'.
Property 'announcementBody' is missing in type 'IListItem'.
I have a base interface and extended interfaces that represent list items in sharepoint depending on the list, a normal list has id, title, createdby, createddate, etc, other lists inherit the same fields, but add additional fields, so my design is like this:
export interface IListItem {
[key: string]: any;
id: string;
title: string;
modified: Date;
created: Date;
modifiedby: string;
createdby: string;
}
import {IListItem} from './IListItem';
export interface INewsListItem extends IListItem {
newsheader: string;
newsbody: string;
expiryDate: Date;
}
import {IListItem} from './IListItem';
export interface IDirectoryListItem extends IListItem {
firstName: string;
lastName: string;
mobileNumber: string;
internalNumber: string;
}
import {IListItem} from './IListItem';
export interface IAnnouncementListItem extends IListItem {
announcementBody: string;
expiryDate: Date;
}
Now, I have a factory method design pattern like this:
import { IListItem } from './models/IListItem';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
export interface IFactory{
getItems(requester: SPHttpClient, siteUrl: string, listName: string): IListItem[];
}
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
import { IWebPartContext } from '#microsoft/sp-webpart-base';
import { IListItem} from './models/IListItem';
import { IFactory } from './IFactory';
import { INewsListItem } from './models/INewsListItem';
import { IDirectoryListItem } from './models/IDirectoryListItem';
import { IAnnouncementListItem } from './models/IAnnouncementListItem';
export class ListItemFactory implements IFactory{
getItems(requester: SPHttpClient, siteUrl: string, listName: string): IListItem[] {
switch(listName) {
case 'List':
let items: IListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: IListItem[] }> => {
return response.json();
})
.then((response: { value: IListItem[] }): void => {
items= response.value;
});
return items;
case 'News':
let newsitems: INewsListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: INewsListItem[] }> => {
return response.json();
})
.then((response: { value: INewsListItem[] }): void => {
newsitems= response.value;
});
return newsitems;
case 'Announcements':
let announcementitems: IAnnouncementListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: IAnnouncementListItem[] }> => {
return response.json();
})
.then((response: { value: IAnnouncementListItem[] }): void => {
announcementitems= response.value;
});
return announcementitems;
case 'Directory':
let directoryitems: IDirectoryListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: IDirectoryListItem[] }> => {
return response.json();
})
.then((response: { value: IDirectoryListItem[] }): void => {
items= response.value;
});
return directoryitems;
default:
return null;
}
}
}
so far so god, however on my react component when I try to use it:
private readItems(): void {
this.setState({
status: 'Loading all items...'
});
let factory = new ListItemFactory();
//Here its where we actually use the pattern to make our coding easier.
switch(this.props.listName)
{
case "List":
let listItems = factory.getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
DetailsListItemState : {
items: listItems,
columns: [
]
}
});
break;
case "Announcements":
let announcementlistItems = factory.getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
DetailsAnnouncementListItemState : {
items: announcementlistItems,
columns: []
}
});
break;
case "News":
let newsFactory = new NewsListItemFactory();
let newsListItems = newsFactory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
DetailsNewsListItemState : {
items: newsListItems,
columns: []
}
});
break;
case "Directory":
let directoryFactory = new DirectoryListItemFactory();
let directoryListItems = directoryFactory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
DetailsDirectoryListItemState : {
items: directoryListItems,
columns: []
}
});
break;
default :
break;
}
}
This is the place where I get the exception, the first switch case works fine, the second one doesnt, and I understand whats happening, getitems return ListItem[], but I am trying to assign the value to an AnnouncementListItem[]
However I am not sure how to fix it, as you could see the newslisitem extends ListItem, and I want to make this solution as generic as possible
Update,
Forgot this file
import { IListItem } from './models/IListItem';
import { INewsListItem } from './models/INewsListItem';
import { IDirectoryListItem } from './models/IDirectoryListItem';
import { IAnnouncementListItem } from './models/IAnnouncementListItem';
import {
IColumn
} from 'office-ui-fabric-react/lib/DetailsList';
export interface IFactoryMethodState{
type: string;
status: string;
DetailsListItemState: IDetailsListItemState;
DetailsNewsListItemState: IDetailsNewsListItemState;
DetailsDirectoryListItemState : IDetailsDirectoryListItemState;
DetailsAnnouncementListItemState : IDetailsAnnouncementListItemState;
}
export interface IDetailsListItemState {
columns: IColumn[];
items: IListItem[];
}
export interface IDetailsNewsListItemState {
columns: IColumn[];
items: INewsListItem[];
}
export interface IDetailsDirectoryListItemState {
columns: IColumn[];
items: IDirectoryListItem[];
}
export interface IDetailsAnnouncementListItemState {
columns: IColumn[];
items: IAnnouncementListItem[];
}
In what follows I am only going to talk about IAnnouncementListItem but you can use the same analysis for each of your subtypes.
The error is correctly telling you that the compiler has no way to verify that factory.getItems() returns an array of IAnnouncementListItem. As you said, IAnnouncementListItem extends IListItem, which means that every IAnnouncementListItem is an IListItem, but not every IListItem is an IAnnouncementListItem. So it is warning you that you are doing something unsafe by treating an array of IListItem as an array of IAnnouncementListItem.
There are multiple ways to deal with it:
Type Assertions
One is to just tell the compiler that you know what you're doing and that it shouldn't worry, by asserting that the return value of factory.getItems() is the right type.
let announcementlistItems = factory.getItems(
this.props.spHttpClient, this.props.siteUrl, this.props.listName
) as IAnnouncementListItem[];
This silences the compiler, but you lose the benefit of the compiler's type checking.
Runtime type guards
Another way is to take the result from getItems() and perform a runtime check to see if the return value is actually an array of IAnnouncementListItem[]. Here's an example:
function isArrayOfIAnnouncementListItem(arr: IListItem[]): arr is IAnnouncementListItem[] {
return arr.every(listItem => 'announcementBody' in listItem);
}
And then
let announcementlistItems = factory.getItems(
this.props.spHttpClient, this.props.siteUrl, this.props.listName
);
if (!isArrayOfIAnnouncementListItem(announcementListItems)) {
throw new Error("Wrong Type or Something");
}
// now announcementListItems is known to be IAnnouncementListItem[]
This will make the compiler happy. It's safer than a bare assertion, but you're still doing runtime checks. If someone else implemented getItems(), this might be the best you could do. But since you're implementing it, you can actually make getItems() itself safer:
Overload signature
Probably the best way to deal with it is to change the signature of getItems() so that it knows that the listName parameter affects the output type. This can be done using overloads:
// overloads
getItems(requester: SPHttpClient, siteUrl: string, listName: "Announcements"): IAnnouncementListItem[];
// put other overloads for each allowable type here
// implementation
getItems(requester: SPHttpClient, siteUrl: string, listName: string): IListItem[] | null; { // .. implementation
(You can get this behavior with generics instead of overloads if you want; more info available upon request)
Now when you call getItems() you will be restricted to using a listName from the set of acceptable values, and the return type will be narrowed for you.
So, you can do any of those if you want. Hope that helps. Good luck!

How to use Interface or Model to access nested JSON in Angular2/4?

I am not able to map the nested json array from my local mock data. The json data is supposed to be like
{
success: true,
data: {
count: 2,
pageNo: 1,
pageSize: 10,
list: [
{
title: 'title',
subtitle: 'subtitle',
priority: 0,
img: ' ',
url: ' '},
{
title: 'title2',
subtitle: 'subtitle',
priority: 0,
img: ' ',
url: ' '}
]
}
}
The service is
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
interface Carousel {
success: boolean;
data: CarouselData;
}
interface CarouselData {
count: number;
pageNo: number;
pageSize: number;
list: CarouselList[];
}
interface CarouselList {
title: string;
subtitle: string;
priority: number;
img: string;
url: string;
}
#Injectable()
export class IndexService {
private carouselUrl = 'api/carousel';
constructor(private http: HttpClient) { }
getCarouselList(): Observable<CarouselData>{
return this.http.get<Carousel>(this.carouselUrl).map(response =>
response.data as CarouselData);
}
}
The component is
carouselList: CarouselData;
ngOnInit():void{
this.indexService.getCarouselList().subscription(response => {
this.carouselList = response;
console.log(response);
})
}
The console log is
enter image description here
I can access the json data in the correct form, but when I try to access the array in the list object, I got a undefined error.
The modification in the service file is
getCarouselList(): Observable<CarouselList[]>{
return this.http.get<Carousel>(this.carouselUrl).map(response =>
response.data.list as CarouselList[]);
}
and the corresponding modification in the component is
carouselList: CarouselList[];
ngOnInit():void{
this.indexService.getCarouselList().subscription(response => {
this.carouselList = response;
console.log(response);
})
}
In the final, the console prints a undefinied object instead of printing the array objects of the list. The compiler and browser don't display any error, but I just can't map the sub-array objects in the list. Can you please help me with this?
Thanks

Resources