Reactjs 类型为'的参数;{状态:字符串;详细信息列表项状态:{items:IListItem[];列:未定义
我有以下错误,下面我将尝试解释我试图实现的目标:Reactjs 类型为'的参数;{状态:字符串;详细信息列表项状态:{items:IListItem[];列:未定义,reactjs,typescript,design-patterns,Reactjs,Typescript,Design Patterns,我有以下错误,下面我将尝试解释我试图实现的目标: [ts] Argument of type '{ status: string; DetailsAnnouncementListItemState: { items: IListItem[]; columns: undefined[]; }...' is not assignable to parameter of type 'Pick<IFactoryMethodState, "status" | "DetailsAnnouncement
[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'.
现在,我有一个工厂方法设计模式,如下所示:
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;
}
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;
}
}
}
这是我得到异常的地方,第一个开关情况工作正常,第二个开关情况不正常,我理解发生了什么,getitems返回ListItem[],但我正在尝试将该值分配给一个AnnouncementListItem[]
但是,我不确定如何修复它,因为您可以看到newslisitem扩展了ListItem,我希望使此解决方案尽可能通用
更新
忘了这个文件
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[];
}
在接下来的内容中,我将只讨论
IANNounceListItem
,但是您可以对每个子类型使用相同的分析
该错误正确地告诉您编译器无法验证
factory.getItems()
返回一个iannounoconnectListItem
数组。正如您所说,iannounoconnectListItem
扩展了iannounoconnectListItem
,这意味着每个iannounoconnectListItem
都是iannounoconnectListItem
,但不是每个IListItem
都是iannounoconnectListItem
。因此它警告您不要这样做通过将IListItem
数组视为iAnonounceListItem
数组来处理不安全的内容
有多种方法可以解决这一问题:
类型断言 一种方法是通过断言
factory.getItems()
的返回值是正确的类型,告诉编译器您知道自己在做什么,而且不必担心
let announcementlistItems = factory.getItems(
this.props.spHttpClient, this.props.siteUrl, this.props.listName
) as IAnnouncementListItem[];
这会使编译器静音,但会失去编译器类型检查的好处
运行时类型保护 另一种方法是从
getItems()
获取结果,并执行运行时检查,以查看返回值是否实际上是IAnnounceListItem[]
的数组
function isArrayOfIAnnouncementListItem(arr: IListItem[]): arr is IAnnouncementListItem[] {
return arr.every(listItem => 'announcementBody' in listItem);
}
然后
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[]
这将使编译器感到高兴。这比简单的断言更安全,但您仍在执行运行时检查。如果其他人实现了getItems()
,这可能是您所能做的最好的事情。但由于您正在实现它,您实际上可以使getItems()
本身更安全:
重载签名 处理此问题的最佳方法可能是更改
getItems()
的签名,以便它知道listName
参数会影响输出类型。这可以通过以下方法完成:
(如果需要,您可以通过泛型而不是重载获得此行为;根据要求,可以获得更多信息)
现在,当您调用getItems()
时,您将被限制使用可接受值集中的listName
,并且返回类型将为您缩小
所以,如果你愿意,你可以做任何一个。希望这有帮助。祝你好运
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[]
// 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