解决__typename联合

时间:2019-05-23 13:11:44

标签: typescript graphql

说我有这个工会:

export type IBookmarkItemFragment =
  | ({ __typename: "Story" } & {
      story: number;
    })
  | ({ __typename: "Product" } & {
      product: number;
    })
  | ({ __typename: "Project" } & {
      project: number;
    });

我希望基于.filter的{​​{1}}和.map。像这样:

__typeame

我如何确保在地图bookmarks .filter(bookmark => { return bookmark.__typename === "Project"; }) .map(project => { return project.project; }); 中将解析为:

project

1 个答案:

答案 0 :(得分:1)

您必须明确声明该函数是带有批注的类型防护:

export type IBookmarkItemFragment =
| ({ __typename: "Story" } & {
    story: number;
    })
| ({ __typename: "Product" } & {
    product: number;
    })
| ({ __typename: "Project" } & {
    project: number;
    });

declare let bookmarks: IBookmarkItemFragment[]
bookmarks
.filter((bookmark):bookmark is Extract<IBookmarkItemFragment, { __typename: "Project"}>   => {
    return bookmark.__typename === "Project";
})
.map(project => {
    return project.project;
});

或者只是出于娱乐目的,如果我们想泛化类型防护,我们可以创建一个防护工厂,该工厂可以对此通用标记联合使用。

export type IBookmarkItemFragment =
| ({ __typename: "Story" } & {
    story: number;
    })
| ({ __typename: "Product" } & {
    product: number;
    })
| ({ __typename: "Project" } & {
    project: number;
    });

function guardFactory<T, K extends keyof T, V extends string & T[K]>(k: K, v: V) : (o: T) => o is Extract<T, Record<K, V>> {
    return function (o: T): o is Extract<T, Record<K, V>> {
        return o[k] === v
    }
}
declare let bookmarks: IBookmarkItemFragment[]
bookmarks
.filter(guardFactory("__typename", "Project"))
.map(project => {
    return project.project;
});