在具有泛型的另一个参数中重用第一个参数的键

Allejo

我一直在尝试用Google搜索如何解决此问题,但即使要提出要查找的内容也很难,因此在编辑此问题或将我链接到重复项方面的任何帮助都将非常有帮助。

用例

我有一个函数,作为第一个参数,将“列名”的记录作为键,将接口字段作为值。例如,

{
  "user_id": "userID",
  "email__": "email",
}

和一个接口,

interface ExpectedShape {
  userID: number;
  email: string;
}

铸件

由于我无法控制的原因,我上面的数据所在的列被命名为user_idemail__,并且将始终以字符串形式返回。因此,我需要定义在创建与ExpectedShape接口匹配的JS对象时如何转换或清除传入的数据

因此,为了允许这样做,我在我的方法中有一个配置变量,该变量将使用原始映射相同的键,但是具有将相应地进行转换的方法。例如,

{
  "user_id": Number.parseInt,
  "email__": sanitizeEmail,
}

因此,当user_id来自数据源时,它将进行调用,Number.parseInt以便在ExpectedShape构建对象,它将是一个适当的数字。

我想做的事

通过TypeScript,我想强制使“映射”和“广播操作”的键相同。

下面是一些码不起作用,但显示了我会想象它的样子。

interface ExpectedShape {
    userID: number;
    email: string;
}

interface FunctionOptions<K extends keyof any, S> {
    casting: Record<K, (value: string) => S[keyof S]>;
}

function myFunction<T extends {}>(
    values: Record<string, keyof T>,
    config: FunctionOptions<keyof values, T>, // <-- What can I put here?
): Partial<T> {
    return {};
}

function sanitizeEmail(_: string): string { return ""; }

const result = myFunction<ExpectedShape>(
    {
      "user_id": "userID",
      "email__": "email",
    },
    {
        // I want to restrict via TypeScript that the keys of `casting` must be
        // the same as the keys of the `values` argument. See how it's missing
        // an underscore?
        casting: {
            userid: Number.parseInt,
        }
    },
);

我尝试过的...

我已经尝试了很多。我最能成功工作并成功编译的是这个,

function myFunction<
    T extends {},
    M extends Record<string, keyof T> = Record<string, keyof T>,
    P extends keyof M = keyof M,
>(
    values: M,
    config: FunctionOptions<P, T>,
): Partial<T> {
    return {};
}

然而。它不能正确执行密钥,并且允许我使用所需的任何密钥。

贾卡尔兹

我认为,为了使其在运行时或在类型系统上都能正常工作,您需要传递类似以下三个参数的内容:您要处理的输入对象;一个将输入对象的键映射到输出对象的键的对象;一个将输入对象的值映射到输出对象的值的对象。假定键映射器将只是其值为键的对象,而值映射器将是其值为功能的对象。

这是一种可能的实现:

function mapKeysAndValues<I extends object,
  KM extends Record<keyof I, S>,
  VM extends { [K in keyof I]: (v: I[K]) => any },
  S extends PropertyKey
>(
  inputObject: I,
  keyMapping: KM,
  valMapping: VM
): { [K in keyof I as KM[K]]: ReturnType<VM[K]> } {

  const ret: any = {};
  (Object.keys(inputObject) as Array<keyof I>).forEach(k =>
    ret[keyMapping[k]] = valMapping[k](inputObject[k] as any)
  )
  return ret;
}

这里有三个重要的泛型类型参数:I对应于输入对象,KM对应于键映射对象和VM对应于值映射对象。

(type参数S除了提供提示我们希望编译器将键映射对象的值解释为文字值,而不是像其他没用的东西之外,并没有其他作用string。有关功能请求,请参阅microsoft / TypeScript#30680进行讨论。您几乎可以忽略S)。

繁重的工作是的返回类型mapKeysAndValues()我们在映射类型中使用键重新映射K,将输入KM[K]中的每个键替换为输出中的键。而我们使用ReturnType<T>工具类型的属性值抓住每个属性的返回类型K的函数VM,并用它作为值类型的输出类型的相应属性。

该实现使用一堆类型断言来防止编译器抱怨(它确实不理解键重映射或相关函数),但是在运行时,您可以看到它几乎只是遍历输入对象键并对每个键执行转换。 。(从技术上讲,inputObject可能具有编译器未知的其他属性,因此您可能希望通过执行其他运行时检查(例如if (k in valMapping)和)来使其更加安全if (typeof valMapping[k] === "function")。但是,我将忽略这种可能性。


让我们测试一下:

const ret: ExpectedShape = mapKeysAndValues(
  { "user_id": "123", "email__": "[email protected]" },
  { "user_id": "userID", "email__": "email" },
  { "user_id": Number.parseInt, "email__": sanitizeEmail }
)

console.log(ret);
/* {
  "userID": 123,
  "email": "[email protected]"
}  */

看起来不错!编译器知道mapKeysAndValues()会产生该ExpectedShape类型的值,并且当我们将其记录到控制台时,我们看到在运行时也发生了正确的事情。

希望您可以将其mapKeysAndValues()用作尝试完成的转换的起点。

操场上的代码链接

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Java泛型的另一个泛型

来自分类Dev

用泛型调用具有相同参数但名称不同的另一个函数会在Swift中引发错误

来自分类Dev

具有可选第一个参数的MVC路由

来自分类Dev

JS中的文本函数第一个参数(_)

来自分类Dev

如何从具有参数的另一个函数中调用带有参数的函数?

来自分类Dev

如何传递具有参数作为另一个函数的参数的函数指针?

来自分类Dev

第一个参数索引

来自分类Dev

当一个方法具有泛型类型参数而另一个方法具有非泛型参数时,java如何确定将调用哪个重载方法?

来自分类Dev

$ @除了第一个参数

来自分类Dev

如何从另一个向量的另一个第一个元素减去向量中的第一个元素?

来自分类Dev

Typescript从函数中删除第一个参数

来自分类Dev

打字稿:另一个参数的键?

来自分类Dev

具有基于另一个参数的默认参数的函数

来自分类Dev

kotlin-如何在另一个参数中重用一个参数的值

来自分类Dev

当一个方法具有泛型类型参数而另一个方法具有非泛型参数时,java如何确定将调用哪个重载方法?

来自分类Dev

如何在一个文件中声明并从另一个文件中调用的参数中编程带有PHP的可重用函数?

来自分类Dev

PHP:在第一个函数内的另一个函数中使用函数参数吗?

来自分类Dev

Java泛型:如何将泛型参数声明为另一个泛型参数的基本类型?

来自分类Dev

具有可变参数的Objective-C方法-跳过第一个参数?

来自分类Dev

具有可选第一个参数的MVC路由

来自分类Dev

$ @除了第一个参数

来自分类Dev

JS中的文本函数第一个参数(_)

来自分类Dev

可以在同一行中重用BASH行的第一个参数吗?

来自分类Dev

使用数组作为参数仅通过第一个元素(JSON RPC)调用PHP中的另一个函数

来自分类Dev

在具有第一个参数预设的方法中传递动作

来自分类Dev

另一个->形式中的第一个参数不能包含nil或为空

来自分类Dev

删除$ *中的第一个参数

来自分类Dev

对于给定的类型参数,如何声明一个特征与另一个泛型特征等效?

来自分类Dev

将泛型类型参数限制为不是 VB.NET 中的另一个泛型类型参数

Related 相关文章

  1. 1

    Java泛型的另一个泛型

  2. 2

    用泛型调用具有相同参数但名称不同的另一个函数会在Swift中引发错误

  3. 3

    具有可选第一个参数的MVC路由

  4. 4

    JS中的文本函数第一个参数(_)

  5. 5

    如何从具有参数的另一个函数中调用带有参数的函数?

  6. 6

    如何传递具有参数作为另一个函数的参数的函数指针?

  7. 7

    第一个参数索引

  8. 8

    当一个方法具有泛型类型参数而另一个方法具有非泛型参数时,java如何确定将调用哪个重载方法?

  9. 9

    $ @除了第一个参数

  10. 10

    如何从另一个向量的另一个第一个元素减去向量中的第一个元素?

  11. 11

    Typescript从函数中删除第一个参数

  12. 12

    打字稿:另一个参数的键?

  13. 13

    具有基于另一个参数的默认参数的函数

  14. 14

    kotlin-如何在另一个参数中重用一个参数的值

  15. 15

    当一个方法具有泛型类型参数而另一个方法具有非泛型参数时,java如何确定将调用哪个重载方法?

  16. 16

    如何在一个文件中声明并从另一个文件中调用的参数中编程带有PHP的可重用函数?

  17. 17

    PHP:在第一个函数内的另一个函数中使用函数参数吗?

  18. 18

    Java泛型:如何将泛型参数声明为另一个泛型参数的基本类型?

  19. 19

    具有可变参数的Objective-C方法-跳过第一个参数?

  20. 20

    具有可选第一个参数的MVC路由

  21. 21

    $ @除了第一个参数

  22. 22

    JS中的文本函数第一个参数(_)

  23. 23

    可以在同一行中重用BASH行的第一个参数吗?

  24. 24

    使用数组作为参数仅通过第一个元素(JSON RPC)调用PHP中的另一个函数

  25. 25

    在具有第一个参数预设的方法中传递动作

  26. 26

    另一个->形式中的第一个参数不能包含nil或为空

  27. 27

    删除$ *中的第一个参数

  28. 28

    对于给定的类型参数,如何声明一个特征与另一个泛型特征等效?

  29. 29

    将泛型类型参数限制为不是 VB.NET 中的另一个泛型类型参数

热门标签

归档