打字稿重构切换语句

时间:2018-06-03 10:47:40

标签: typescript

我有一个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.

1 个答案:

答案 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>