是否有一种方法可以限制下面的run
调用,使其严格限制为RequestType<>
指定的类型参数所允许的类型?返回类型R
似乎有效,但是RQ
并不严格。
class RequestType<RQ, R> {
constructor(public readonly method: string) { }
}
interface FooRequest {
foo: string;
bar: string;
}
interface FooResponse {
foobar: string;
}
const FooRequestType = new RequestType<FooRequest, FooResponse>("foo");
function run<RQ, R>(type: RequestType<RQ, R>, request: RQ): R {
// real code here
return {} as R;
}
这是电话
const foo1 = run(FooRequestType, {}); // want an error here
const foo2 = run(FooRequestType, {
foo: "foo" // want an error here
});
const foo3 = run(FooRequestType, {
foo: "foo",
bar: "bar",
baz: "" // error here -- good
});
这里是TypeScript playgound的链接。感谢您的帮助-谢谢!
答案 0 :(得分:1)
来自docs:由于TypeScript是结构类型系统,所以类型参数仅在作为成员类型的一部分使用时才影响结果类型。
在您的情况下,RequestType<{},FooResponse>
和RequestType<FooRequest, FooResponse>
具有完全相同的结构,因此顺应
run(FooRequestType, {});
类型正确推断为
run<{},FooResponse>(FooRequestType: RequestType<{}, FooResponse>, {}: {})
一种解决方法是在RequestType
中添加一些(如果需要的话是伪造的)属性,以使RequestType<RQ1,R>
与RequestType<RQ2,R>
不同。该属性可能是
class RequestType<RQ, R> {
private readonly acc: (req: RQ) => RQ | undefined;
constructor(public readonly method: string) { }
}
请注意,要使此特定解决方案成功,您需要启用strictFunctionTypes
选项。否则,(req: FooRequest) => FooRequest
将可分配给(req: {}) => {}
,因此FooRequestType
仍将可分配给RequestType<{}, FooResponse>
。您可以详细了解here。
另一种方法是不允许TypeScript为request
推断错误的类型,而是使其为requestType
推断类型(出于可读性而从type
更改):< / p>
type RequestOf<RT> = RT extends RequestType<infer RQ, any> ? RQ : never;
type ResponseOf<RT> = RT extends RequestType<any, infer R> ? R : never;
function run<RT extends RequestType<any, any>>(
requestType: RT,
request: RequestOf<RT>
): ResponseOf<RT> {
return {} as ResponseOf<RT>;
}
现在,TypeScript将正确地“猜测” RT
是RequestType<FooRequest, FooResponse>
。然后,
type RequestOf<RT> = RT extends RequestType<infer RQ, any> ? RQ : never;
基本上说:如果RT
是RequestType<RQ, something>
,则使RequestOf<RT>
等于RQ
。有关infer
魔术的更多信息,请参见Type inference in conditional types。