【问题标题】:Intersection of an object's value types in TypeScriptTypeScript 中对象值类型的交集
【发布时间】:2021-03-02 18:27:05
【问题描述】:

我有一个 TypeScript interface,它定义了我可以在 REST 端点上使用的 HTTP 方法和查询参数类型(请参阅 crosswalk 了解您为什么要这样做的详细信息):

interface API {
  '/endpoint': {
    get: {a?: string, b?: string};
    post: {b?: string, c?: string};
  } 
}

我想定义一个函数,该函数采用此 API 类型、端点 ('/endpoint') 以及可选的 HTTP 动词('get''post' 等)和适当的查询参数:

const urlMaker = apiUrlMaker<API>();
urlMaker('/endpoint')({a: 'a', b: 'b'});  // should be an error, we don't know that "a" is OK.
urlMaker('/endpoint')({b: 'b'});  // fine, "b" is always safe. Should return "/endpoint?b=b".
urlMaker('/endpoint', 'get')({a: 'a', b: 'b'});
// fine, we're explicitly using get. Should return "/endpoint?a=a&b=b".

在用户省略 HTTP 动词的情况下,我想接受此方法的查询参数类型的交集(即可以传递给任何动词的查询参数类型)。

我可以通过这种方式获得类型的 union

type ParamUnion = API['/endpoint'][keyof API['/endpoint']];
// type is {a?: string, b?: string} | {b?: string, c?: string}

我知道converting unions to intersections 的诀窍,但我想知道在这种情况下是否有一种方法可以不通过联合。当然,除了getpostdeleteputpatch 等)之外,还可以为端点定义任意数量的 HTTP 动词。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    我会使用相同的基本技术,因为据我所知,conditional type inference with infer 是 TS 中唯一可以自动生成任意数量类型的交集的功能(无需求助于递归)。您不必显式地先通过联合,尽管它仍然隐含在其中:

    type ParamIntersection = {
      [K in keyof API['/endpoint']]: (x: API['/endpoint'][K]) => void
    }[keyof API['/endpoint']] extends
      (x: infer I) => void ? I : never;
    
    /* type ParamIntersection = {
        a?: string | undefined;
        b?: string | undefined;
    } & {
        b?: string | undefined;
        c?: string | undefined;
    } */
    

    我将每个属性类型转换为函数的参数,然后获取这些函数的联合,并从中推断出单个参数,这通过函数参数逆变的魔力将联合变为交集。

    这种类型有点难看,如果有更多的交集构成会变得更糟,所以你也可以将它们合并成一个对象类型:

    type ParamMerged = {
      [K in keyof API['/endpoint']]: (x: API['/endpoint'][K]) => void
    }[keyof API['/endpoint']] extends
      (x: infer I) => void ? { [K in keyof I]: I[K] } : never;
    
    /* type ParamIntersection = {
        a?: string | undefined;
        b?: string | undefined;
        c?: string | undefined;
    } */
    

    Playground link to code

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 2020-07-16
      • 1970-01-01
      • 2020-05-21
      • 2021-10-18
      • 2019-11-01
      • 2022-11-28
      • 2020-05-13
      • 1970-01-01
      相关资源
      最近更新 更多