对象的交点';TypeScript中的s值类型

对象的交点';TypeScript中的s值类型,typescript,Typescript,我有一个TypeScript接口,它定义了我可以在REST端点上使用的HTTP方法和查询参数类型(有关为什么要这样做的详细信息,请参阅): 我想定义一个采用此API类型的函数、端点('/endpoint')和HTTP谓词('get'、'post')以及适当的查询参数: const urlMaker = apiUrlMaker<API>(); urlMaker('/endpoint')({a: 'a', b: 'b'}); // should be an error, we don'

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

我想定义一个采用此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".

我知道的诀窍,但我想知道是否有一种方法可以做到这一点,在这种情况下,不通过工会。当然,除了
get
post
delete
put
patch
,等等)之外,可以为一个端点定义任意数量的HTTP动词,是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;
} */

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;
} */