[英]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
,如果类型A
和B
的交集满足类型Options
,则两个...
rest 参数将属于A
和B
类型。 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.