我有一个switch语句,但每个case的内容非常相似,基本上唯一的区别是REST调用中带有select属性的URL,以及当json结果转换为特定特定集合时的.then类型。
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 {
// private _listItems: IListItem[];
public getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any[]> {
switch(listName) {
case "GenericList":
let items: IListItem[];
// tslint:disable-next-line:max-line-length
return requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
SPHttpClient.configurations.v1,
{
headers: {
"Accept": "application/json;odata=nometadata",
"odata-version": ""
}
})
.then((response: SPHttpClientResponse): Promise<{ value: IListItem[] }> => {
return response.json();
})
.then((json: { value: IListItem[] }) => {
console.log(JSON.stringify(json.value));
return items=json.value.map((v,i)=>(
{
// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title
}
));
});
case "News":
let newsitems: INewsListItem[];
// tslint:disable-next-line:max-line-length
return requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
SPHttpClient.configurations.v1,
{
headers: {
"Accept": "application/json;odata=nometadata",
"odata-version": ""
}
})
.then((response: SPHttpClientResponse): Promise<{ value: INewsListItem[] }> => {
return response.json();
})
.then((json: { value: INewsListItem[] }) => {
return newsitems=json.value.map((v,i)=>(
{
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate
}
));
});
case "Announcements":
let announcementitems: IAnnouncementListItem[];
return requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
SPHttpClient.configurations.v1,
{
headers: {
"Accept": "application/json;odata=nometadata",
"odata-version": ""
}
})
.then((response: SPHttpClientResponse): Promise<{ value: IAnnouncementListItem[] }> => {
return response.json();
})
.then((json: { value: IAnnouncementListItem[] }) => {
return announcementitems=json.value.map((v,i)=>(
{
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate
}
));
});
case "Directory":
let directoryitems: IDirectoryListItem[];
return 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((json: { value: IDirectoryListItem[] }) => {
return directoryitems=json.value.map((v,i)=>(
{
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber
}
));
});
default:
break;
}
}
}
更新1
根据答案我改变了IFactory.ts
import { IListItem } from "./models/IListItem";
import { SPHttpClient, SPHttpClientResponse } from "@microsoft/sp-http";
import { ListItemFactory } from "./ListItemFactory";
export interface IFactory {
getItems<K extends keyof ListItemFactory['handlers']>(requester: SPHttpClient, siteUrl: string, listName: K): Promise<ReturnType<ListItemFactory['handlers'][K]['process']>> ;
//getItems(requester: SPHttpClient, siteUrl: string, listName: string): Promise<any[]>;
}
ListItemFactory.ts
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 {
private handlers = {
GenericList : {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
async process(result: any) {
const json: { value: IListItem[] } = result;
return json.value.map((v,i)=>({
// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title
}));
}
},
News: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
async process(result: any) {
const json: { value: INewsListItem[] } = result;
return json.value.map((v,i)=>(
{
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate
}
));
}
},
Announcements: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
async process(result: any) {
const json: { value: IAnnouncementListItem[] } = result;
return json.value.map((v,i)=>({
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate
}));
}
},
Directory: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
process(result: any) {
const json: { value: IDirectoryListItem[] } = result;
return json.value.map((v,i)=>({
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber
}));
}
}
};
public async getItems<K extends keyof ListItemFactory['handlers']>(requester: SPHttpClient, siteUrl: string, listName: K): Promise<ReturnType<ListItemFactory['handlers'][K]['process']>> {
var h = this.handlers[listName];
const response = await requester.get(
h.url(siteUrl, listName),
SPHttpClient.configurations.v1,
{
headers: {
"Accept": "application/json;odata=nometadata",
"odata-version": ""
}
});
var json = response.json();
return h.process(json) as any;
}
}
但是我得到了这个错误
[19:42:56] Error - typescript - src/webparts/factoryMethod/components/IFactory.ts(5,122): error TS2304: Cannot find name 'ReturnType'.
[19:42:56] Error - typescript - src/webparts/factoryMethod/components/ListItemFactory.ts(80,135): error TS2304: Cannot find name 'ReturnType'.
[19:42:56] Error - typescript - src/webparts/factoryMethod/components/IFactory.ts(5,122): error TS4057: Return type of method from exported interface has or is using private name 'ReturnType'.
[19:42:56] Error - typescript - src/webparts/factoryMethod/components/ListItemFactory.ts(80,135): error TS4055: Return type of public method from exported class has or is using private name 'ReturnType'.
[19:42:56] Finished subtask 'tslint' after 2.93 s
[19:42:56] Error - 'typescript' sub task errored after 2.06 s
TypeScript error(s) occurred.
答案 0 :(得分:1)
我会从每个开关中取出公共部分,并在地图对象中移动不同的部分。不常见的部分似乎是网址以及如何处理结果。
我们也可以使用返回类型和列表类型做得更好。我们将密钥限制为仅受支持的值之一,并且具有特定于传入的listName
的返回类型。
export class ListItemFactory implements IFactory {
handlers = {
GenericList : {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Author/Title,Editor/Title&$expand=Author,Editor`,
async process(result: any) {
const json: { value: IListItem[] } = result;
return json.value.map((v,i)=>({
// key: v.id,
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title
}));
}
},
News: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Modified,Created,Created By,Modified By,newsheader,newsbody,expiryDate`,
async process(result: any) {
const json: { value: INewsListItem[] } = result;
return json.value.map((v,i)=>(
{
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
newsheader: v.newsheader,
newsbody: v.newsbody,
expiryDate: v.expiryDate
}
));
}
},
Announcements: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id,Created,Author/Title,Modified,Editor/Title,announcementBody,expiryDate&$expand=Author,Editor`,
async process(result: any) {
const json: { value: IAnnouncementListItem[] } = result;
return json.value.map((v,i)=>({
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
announcementBody: v.announcementBody,
expiryDate: v.expiryDate
}));
}
},
Directory: {
url: (siteUrl: string, listName: string) => `${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
process(result: any) {
const json: { value: IDirectoryListItem[] } = result;
return json.value.map((v,i)=>({
id: v.Id,
title: v.Title,
created: v.Created,
createdby: v.Author.Title,
modified: v.Modified,
modifiedby: v.Editor.Title,
firstName: v.firstName,
lastName: v.lastName,
mobileNumber: v.mobileNumber,
internalNumber: v.internalNumber
}));
}
}
}
public async getItems<K extends keyof ListItemFactory['handlers']>(requester: SPHttpClient, siteUrl: string, listName: K): Promise<ReturnType<ListItemFactory['handlers'][K]['process']>> {
var h = this.handlers[listName];
const response = await requester.get(
h.url(siteUrl, listName),
SPHttpClient.configurations.v1,
{
headers: {
"Accept": "application/json;odata=nometadata",
"odata-version": ""
}
});
var json = response.json();
return h.process(json) as any;
}
}
let fact = new ListItemFactory();
let requester!: SPHttpClient;
let siteUrl = ''
var genList = fact.getItems(requester, siteUrl, 'GenericList'); // Promise<Promise<{id: any;title: any;created: any;createdby: any;modified: any;modifiedby: any;}[]>>
var dirList = fact.getItems(requester, siteUrl, 'Directory'); // Promise<{id: any;title: any;created: any;createdby: any;modified: any;modifiedby: any;firstName: any;lastName: any;mobileNumber: any;internalNumber: any;}[]>
修改强>
对getItems
签名的一些解释。该方法现在是通用的,类型参数K
必须是处理程序对象的键。此限制是使用keyof T
完成的,T
提供了表示ListItemFactory['handlers']
和handlers
公钥的类型,这是一种类型查询,并为我们提供了K extends keyof ListItemFactory['handlers']
字段的类型,因此我们得到listName
。
现在参数'GenericList'
的值只能是'News'
,'Announcements'
,'Directory'
或K
,当我们调用metod时,取决于在getItems
中传递的值将是表示其中一个值的string literal类型。
我们现在想要将process
的返回值与传入的listName
的{{1}}函数的返回类型联系起来。我们将listName
作为字符串K
中的文字类型为了获得处理程序的类型,我们可以使用类型查询:ListItemFactory['handlers'][K]
向下钻取以获取我们获得的process
函数的类型ListItemFactory['handlers'][K]['process']
。
要获取此函数类型的返回类型,我们使用内置条件类型ReturnType<T>
。 ReturnType<()=> number>
将为number
,如果我们传入函数类型,则类型执行其名称所暗示的值我们得到它的返回值
总而言之,我们得到了Promise<ReturnType<ListItemFactory['handlers'][K]['process']>>
修改强>
对于2.4.2,您不能使用条件类型(它们仅在2.8之后可用)。
你可以像原始代码一样使用any
作为返回类型(不理想,但这是我们在2.4.2中可以做的,理想情况下你应该尝试更新到更新的版本):
public async getItems<K extends keyof ListItemFactory['handlers']>(requester: SPHttpClient, siteUrl: string, listName: K): Promise<any>