[英]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
:我们可以为类型参数指定一个显式类型参数,然后强制它采用错误的
key
和value
组合:
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
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.