程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了如何键入具有不同参数组合的函数?类似于方法重载大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决如何键入具有不同参数组合的函数?类似于方法重载?

开发过程中遇到如何键入具有不同参数组合的函数?类似于方法重载的问题如何解决?下面主要结合日常开发的经验,给出你关于如何键入具有不同参数组合的函数?类似于方法重载的解决方法建议,希望对你解决如何键入具有不同参数组合的函数?类似于方法重载有所启发或帮助;

我希望能够以至少 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 将是 StringRecord<String,String>。我错过了什么吗?或者这根本不可能?

非常感谢您的帮助,谢谢!

解决方法

@H_197_38@

您遇到了 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% 的几率在这里出现一些运行时丑陋。

没有使用泛型甚至使用单独的 typepayload 参数的完美解决方案。无论您做什么,编译器都不会看到这些参数之间的相关性。有关此限制的讨论,请参阅 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 之前,我无法分解为 payloadargs[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,请注明来意。
标签: