大佬教程收集整理的这篇文章主要介绍了如何键入具有不同参数组合的函数?类似于方法重载,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我希望能够以至少 3 种不同的方式调用以下函数:
setbody(payload: Record<String,unkNown>);
setbody(payload: String | Record<String,String>,type: 'urlencoded');
setbody(payload: Blob,type: 'blob');
为了实现这个功能,我尝试了以下方法:
type Payload<T extends 'Json' | 'urlencoded' | 'blob'> =
T extends 'Json'
? Record<String,unkNown>
: T extends 'urlencoded'
? String | Record<String,String>
: Blob;
export const setbody = <T extends 'Json' | 'urlencoded' | 'blob'>(
payload: Payload<T>,type: T,): BodyInit => {
let body;
switch (typE) {
case 'Json':
body = JsON.Stringify(payload);
break;
case 'urlencoded':
body = new URLSearchParams(payload);
break;
default:
body = payload;
}
return body;
};
但是,我收到以下错误:
Type 'Record<String,unkNown> | (T extends "urlencoded" ? String | Record<String,String> : Blob)' is not assignable to type 'String | URLSearchParams | Record<String,String> | String[][] | undefined'.
Type 'Record<String,unkNown>' is not assignable to type 'String | URLSearchParams | Record<String,String> | String[][] | undefined'.
Type 'Record<String,unkNown>' is not assignable to type 'String'.
Type 'String | Record<String,unkNown> | Blob | Record<String,String>' is not assignable to type 'String | URLSearchParams | Record<String,String> | String[][] | undefined'.
Type 'Record<String,String> | String[][] | undefined'.
Type 'Record<String,unkNown>' is not assignable to type 'String'.
Type 'Payload<T>' is not assignable to type 'String[][]'.
Type 'Record<String,String> : Blob)' is not assignable to type 'String[][]'.
Type 'Record<String,unkNown>' is missing the following propertIEs from type 'String[][]': length,pop,push,concat,and 26 more.
Type 'String | Record<String,String>' is not assignable to type 'String[][]'.
Type 'String' is not assignable to type 'String[][]'.
为什么?如果我向 case
添加一个 switch
,但不是上述任何一个,那么 TypeScript 可以确定它永远不会被到达。但不知何故,它无法确定类型是否为 urlencoded
,那么 payload
将是 String
或 Record<String,String>
。我错过了什么吗?或者这根本不可能?
非常感谢您的帮助,谢谢!
您遇到了 TypeScript 的一些限制。一是类型参数扩展联合(如T extends 'json' | 'urlencoded' | 'blob'
)的泛型函数不能被控制流分析缩小。仅检查 type
不足以让编译器缩小 T
本身的范围。有关此问题的详细信息,请参阅 microsoft/TypeScript#24085。不过,事实证明这是有充分理由的。考虑:
setBody({ a: 123 },Math.random() < 0.5 ? "json" : "blob");
// const Orig.setBody: <"json" | "blob">(
// payload: Blob | Record<String,unknown>,type: "json" | "blob") => BodyInit
这里我们为 "json" | "blob"
传入一个 type
类型的值。如果在运行时结果是 "blob"
,编译器会做一些意想不到的事情,因为我们传递的 payload
只能分配给 Payload<"json">
。我们有 50% 的几率在这里出现一些运行时丑陋。
没有使用泛型甚至使用单独的 type
和 payload
参数的完美解决方案。无论您做什么,编译器都不会看到这些参数之间的相关性。有关此限制的讨论,请参阅 microsoft/TypeScript#30581。
我在这里建议您重构为一个非泛型,它采用 discriminated union 的 rest tuple types 的其余参数:
type PayloadAndType =
[payload: Record<String,type: 'json'] |
[payload: String | Record<String,String>,type: 'urlencoded'] |
[payload: Blob,type: 'blob']
export const setBody = (...args: PayloadAndTypE): BodyInit => {
let body: BodyInit;
switch (args[1]) {
case 'json':
body = JSON.Stringify(args[0]);
break;
case 'urlencoded':
body = new URLSearchParams(args[0]);
break;
default:
body = args[0];
}
return body;
};
从调用者的角度来看,这几乎与重载函数相同。 IntelliSense 甚至将其报告为此类。这很好,因为它会接受您想要的电话并拒绝上面有问题的电话:
setBody({ a: 123 },"json"); // okay
setBody(new Blob(),"blob"); // okay
setBody({ a: 123 },Math.random() < 0.5 ? "json" : "blob"); // error!
// Object literal may only specify known properties,and 'a' does not exist in type 'Blob'.
在实现内部,编译器现在可以遵循逻辑。 args[1]
是判别联合对象 args
的判别式,检查它会导致 args[0]
被缩小到相应的负载。请注意,args
的类型为 PayloadAndtype
;在检查 type
之前,我无法分解为 payload
和 args[1]
变量,或者编译器不再将它们视为相关(因此“缺乏相关性”工会支持”上面链接的问题)。您可以在之后检查,但这是多余的:
switch (args[1]) {
case 'json':
{
const [payload,type] = args;
body = JSON.Stringify(payload);
break;
}
case 'urlencoded':
{
const [payload,type] = args;
body = new URLSearchParams(payload);
break;
}
default:
{
const [payload,type] = args;
body = payload;
}
}
Playground link to code
,作为一种解决方法,我可以建议在传递给 URLSearchParams 时强制转换类型。
type Payload<T extends 'json' | 'urlencoded' | 'blob'> = T extends 'json'
? Record<String,unknown>
: T extends 'urlencoded'
? String[][] | Record<String,String> | String | URLSearchParams
: Blob;
const setBody = <T extends 'json' | 'urlencoded' | 'blob'>(payload: Payload<T>,type: T): BodyInit => {
let body;
switch (typE) {
case 'json':
body = JSON.Stringify(payload);
break;
case 'urlencoded':
body = new URLSearchParams(payload as String);
break;
default:
body = payload;
}
return body;
};
所有类型检查都必须正常工作。
以上是大佬教程为你收集整理的如何键入具有不同参数组合的函数?类似于方法重载全部内容,希望文章能够帮你解决如何键入具有不同参数组合的函数?类似于方法重载所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。