简体   繁体   English

限制两个泛型的组合

[英]restriction on combination of two generics

Is there a way in TypeScript to express "You can pass in any two objects, as long as their combination satisfies type X"? TypeScript 有没有办法表达“你可以传入任意两个对象,只要它们的组合满足类型 X”?

So, if I have the following function:所以,如果我有以下功能:

function myFunction(options: {x: number, y: string}){
}

And then, I have a function, that wants to call this function using an combination of two objects:然后,我有一个函数,它想使用两个对象的组合来调用这个函数:

function callMyFunction<A,B>(a:A,b:B){
    myFunction({...a,...b})
} 

And then it would compile if I did one of the following:然后,如果我执行以下操作之一,它将编译:

callMyFunction({},{x:1,y:"hello"})
callMyFunction({x:1},{y:"hello"})
callMyFunction({x:1,y:"hello"},{})

But would not compile if I did for example:但是,如果我这样做,则不会编译:

callMyFunction({x:1},{}) //y missing
callMyFunction({},{y:"hello"}) //x missing
callMyFunction({},{}) //x and y missing

I know that it's possible to restrict a generic type using extends .我知道可以使用extends限制泛型类型。 But is there a way to restrict the combination of two generic types?但是有没有办法限制两种泛型的组合呢? I imagine something like this:我想象这样的事情:

function callMyFunction<A,B, A&B extends {x:number,y:string}>(a:A,b:B){
    myFunction({...a,...b})
}

Is there a way in TypeScript to express "You can pass in any two objects, as long as their combination satisfies type X"? TypeScript 有没有办法表达“你可以传入任意两个对象,只要它们的组合满足类型 X”?

This is a terrific question!这是一个很棒的问题! And the answer is YES.答案是肯定的。

Here is an approach (with a playground link) .这是一种方法(带有游乐场链接) The approach uses a heady mix of TypeScript and JavaScript features.该方法使用了令人兴奋的 TypeScript 和 JavaScript 功能组合。 It uses generics, rest ... parameters, array destructuring, conditional types, the never type, and a tuple type.它使用泛型、rest ...参数、数组解构、条件类型、 never类型和元组类型。 It also tells the compiler that "we know more than it does" by using the as unknown as Options technique.它还通过使用与as unknown as Options技术告诉编译器“我们知道的比它知道的多”。

type Options = { x: number; y: string };
function myFunction(options: Options) {}

function callMyFunction<A, B>(
  ...[a, b]: A & B extends Options ? [A, B] : never
) {
  const options = { ...a, ...b };
  myFunction((options as unknown) as Options);
}

In callMyFunction , if the intersection of types A and B satisfies the type Options , then the two ... rest parameters will be of type A and B .callMyFunction ,如果类型AB的交集满足类型Options ,则两个... rest 参数将属于AB类型。 If the intersection does not satisfy the type Options , then the rest parameters are of type never , which in turn tells the type checker to complain.如果交集不满足Options类型,则其余参数的类型为never ,这反过来告诉类型检查器抱怨。

The result is that these all pass type checking...结果是这些都通过了类型检查……

callMyFunction({}, { x: 1, y: "hello" });
callMyFunction({ x: 1 }, { y: "hello" });
callMyFunction({ x: 1, y: "hello" }, {});

...and that none of these pass type checking. ...并且这些都没有通过类型检查。

/**
 * Argument of type `'[{ x: number; }, {}]'` is not assignable
 * to parameter of type `'never'`.ts(2345)
 */
callMyFunction({ x: 1 }, {});

/**
 * Argument of type `'[{}, { y: string; }]'` is not assignable
 * to parameter of type `'never'`.ts(2345)
 */
callMyFunction({}, { y: "hello" });

/**
 * Argument of type `'[{}, {}]'` is not assignable
 * to parameter of type `'never'`.ts(2345)
 */
callMyFunction({}, {});

The resultant error messages could use improvement.由此产生的错误消息可以使用改进。 As is, the error messages do not tell developers much about the required arguments.照原样,错误消息并没有告诉开发人员太多关于所需参数的信息。 Someone with more TypeScript knowledge than I have can chime in about whether we can improve the error message or not.比我拥有更多 TypeScript 知识的人可以谈谈我们是否可以改进错误消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM