简体   繁体   English

如何在 Typescript 中映射函数的两个参数的类型?

[英]How to map types of two arguments of function in Typescript?

How to implement such functionality?如何实现这样的功能?

type SomeType = {
  name: string;
  quantity: number;
};
const someFunc = (
  key: keyof SomeType /* what should be here?  */,
  value: SomeType[keyof SomeType] /* what should be here?  */
) => {
  // ...
};
someFunc("name", "John") // OK
someFunc("name", 10) // must be error
someFunc("quantity", "John") // must be error
someFunc("quantity", 10) // OK

I've tried this:我试过这个:

...
const someFunc = (
  key: keyof SomeType
  value: SomeType[keyof SomeType]
)
...

But that doesn't work and I understand why.但这行不通,我明白为什么。 So I don't know how to implement this.所以我不知道如何实现这个。

I don't think there's a 100% foolproof way to do this.我认为没有 100% 万无一失的方法可以做到这一点。 You can get close with a generic type parameter:您可以使用泛型类型参数关闭:

type SomeType = {
    name: string;
    quantity: number;
};
const someFunc = <Key extends keyof SomeType>(
    key: Key,
    value: SomeType[Key],
) => {
    // ...
};

With that, your examples work:这样,您的示例就可以工作了:

someFunc("name", "John") // OK
someFunc("name", 10) // Error as desired
someFunc("quantity", "John") // Error as desired
someFunc("quantity", 10) // OK

But , because of unions, it isn't 100%.但是,由于工会,它不是 100%。 We can specify an explicit type argument for the type parameter, and then force it to take the wrong combination of key and value :我们可以为类型参数指定一个显式类型参数,然后强制它采用错误的keyvalue组合:

someFunc<"name" | "quantity">("name", 10) // wrong, but no error

That has ramifications for the code inside the function, since you'd expect narrowing the type of key to narrow the type of value , but it doesn't;这对函数内部的代码有影响,因为您希望缩小key的类型以缩小value的类型,但事实并非如此; see this question's answers .看到这个问题的答案

not so ideal foolproof improvement over @TJ Crowder solution对@TJ Crowder 解决方案的万无一失的改进并不是那么理想

It stops you from using union but does not check the correctness of value type它阻止您使用 union 但不检查值类型的正确性

type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true

type SomeType = {
    name: string;
    quantity: number;
    age: number
};
const someFunc = <Key extends keyof SomeType>(
    key: IsUnion<Key> extends true ? "No Union!" : Key,
    value: SomeType[Key],
) => {
    // ...
};

someFunc<"name" | "quantity">("name", 10) //  error at argument 1, ideally should error at argument 2, but still an error regardless, a true negative case
someFunc<"quantity" | "age">("quantity", 10) //  should not error, because both quantity and age are number, a false negative case

// still works as normal
someFunc("name", "John") // OK
someFunc("name", 10) // Error as desired
someFunc("quantity", "John") // Error as desired
someFunc("quantity", 10) // OK

在此处输入图像描述 playground 操场

IsUnion 是联盟

as shown in the code, not only it error on the wrong argument, there is also a false negative case如代码所示,不仅在错误的参数上出错,还有一个假阴性的情况

but does it matter?但这有关系吗? No it doesn't不,它没有

because you are forced to fix errors by removing the union regardless, clearing the false negative case will not open up to another type error因为无论如何都必须通过删除联合来修复错误,所以清除假阴性案例不会导致另一种类型的错误

so the end result is, it will still leads you to the correct type所以最终结果是,它仍然会引导您找到正确的类型

It is not an ideal method, but it works, it is an example of better be safe than wrong这不是一个理想的方法,但它是有效的,它是安全总比错误好

One problem is this is not newbies friendly, it requires the study of the background problem to understand why the code is written in such way and why the error appear on the wrong argument or appear for no reason.一个问题是这对新手不友好,需要研究背景问题才能理解代码为什么这样写,为什么错误出现在错误的参数上或无缘无故出现。

For those newbies, they will end up in unfruitful troubleshooting every single time, and we all know that the next thing they do is to doubt the purpose of their very own existence对于那些新手来说,每次都会以失败告终,而我们都知道,他们接下来要做的就是怀疑自己存在的意义

There is no way you can explain this like you explaining to a 5 years old, so TS should take the blame你不可能像你给一个 5 岁的孩子解释的那样,所以 TS 应该承担责任

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Typescript:如何通过高级类型将 map 类型数组区分为不同的 arguments? - Typescript: how to map array of types to distinct arguments via advanced types? TypeScript:如何在破坏参数时指定函数参数的类型? - TypeScript: How to specify types for function arguments when destructing arguments? TypeScript 中被破坏的函数参数的类型? - Types for destructed function arguments in TypeScript? TypeScript:函数的两个参数类型 - TypeScript: two argument types for function 如何在 typescript 中使用多种类型的数组调用 map function - How to call map function with array of multiple types in typescript Typescript function arguments 基于以枚举为键的类型 - Typescript function arguments based on types with enums as keys typescript:您将如何返回具有相同 arguments 但不同类型的新 function 的 ZDBC11CAA5BDA929F77E6FB4DBEDA88 - typescript: How would you return a new function with the same arguments but different types for those arguments? 如何在箭头函数中使用 Typescript 泛型添加两个参数 - How to add two arguments using Typescript Generics in Arrow Function 在 Typescript 中传递类型为 arguments - Passing types as arguments in Typescript Typescript 匹配 function 类型和参数类型的 map - Typescript match between map of function types and argument types
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM