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

oiopk7p5  于 2022-12-19  发布在  TypeScript
关注(0)|答案(2)|浏览(160)

如何实现这样的功能?

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

我试过这个:

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

但这行不通,我明白为什么,所以我不知道如何实现它。

rdrgkggo

rdrgkggo1#

我不认为有一个100%万无一失的方法可以做到这一点。你可以用一个泛型类型参数来接近:

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

这样,您的示例就可以发挥作用:

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

但是,因为联合,它不是100%,我们可以为类型参数指定一个显式类型参数,然后强制它接受keyvalue的错误组合:

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

这对函数内部的代码有影响,因为您希望通过缩小key的类型来缩小value的类型,但事实并非如此;参见this question's answers

flvtvl50

flvtvl502#

与@T.J Crowder解决方案相比,改进效果不太理想
它阻止您使用联合,但不检查值类型的正确性

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

x1c 0d1x操场
IsUnion
如代码中所示,它不仅在错误的参数上出错,而且还有一个假否定的情况
但这有关系吗?不,没关系
因为无论如何都要通过移除联合来强制修复错误,所以清除假否定大小写不会导致另一个类型错误
所以最终的结果是,它仍然会引导您找到正确的类型
这不是一个理想的方法,但它的工作,这是一个例子,更好地是安全比错误
一个问题是这不是新手友好的,它需要研究背景问题才能理解为什么代码是这样写的,为什么错误出现在错误的参数上或无缘无故地出现。
对于那些新手来说,他们每一次都将以徒劳的故障排除而告终,我们都知道,他们接下来要做的就是怀疑自己存在的目的
你不可能像对一个5岁的孩子那样解释这件事,所以TS应该承担责任

相关问题