Typescript重构开关语句

路易·瓦伦西亚

我有一个switch语句,但是每种情况下的内容都非常相似,基本上唯一的区别是REST调用中具有select属性的URL,以及.then,当json结果转换为特定类型的特定集合时。

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.
提香·切尔尼科娃·德拉戈米尔

我将从每个开关中取出通用部分,然后将不同部分移动到地图对象中。罕见的部分似乎是网址以及如何处理结果。

同样,我们可以使用返回类型和列表类型做得更好。我们将键限制为仅是支持的值之一,并且具有特定于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必须是handlers对象的键。通过使用来完成此限制keyof T,它给出了表示的公钥的类型,T并且ListItemFactory['handlers']是类型查询,并给出了handlers字段的类型,因此我们将其全部得到K extends keyof ListItemFactory['handlers']

现在参数listName只能具有的值'GenericList'当我们调用方法时,根据传入的值将是表示这些值之一字符串文字类型。'News''Announcements''Directory'K

现在,我们想将返回值绑定getItems传入process函数的返回类型listName。我们将inlistName作为字符串文字类型,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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章