所以你现在可能已经猜到了,要做到这一点,你不能只定义一个像
这样的可索引类型
type FormValues<T> = {
[key: string]: T
}
因为在这种情况下T 将是一个没有太大帮助的联合。
所以你不能使用可索引类型,现在我能想到的唯一方法是停止尝试自己创建类型,让 typescript 为你推断它。
首先让我稍微更改一下您的FormValue 声明,我将删除ValueOf,当我在玩您的沙盒时,我忘记了它的用途,但如果我认为这对我的方式不重要我建议。所以让我们这样输入:
type FormValue<TName extends string, TValue> = {
value: TValue
name: TName
pristine: boolean
errors: string[] | null
}
现在这将只接受两个类型参数,一个是名称,另一个是值,没有不必要的对象。现在让我们输入InitialFormValues:它只是一个具有随机属性的对象,我们不会用它来输入任何东西,只用于约束类型:
type InitialValues = {
[key: string]: any
}
// or
type InitialValues = Record<string, any>
接下来是UseFormProps。这里我们避免创建可索引类型,这不会导致任何结果,但我们让 typescript 为我们推断类型。我们只需要对它进行一点限制,这样就不可能通过 p.e.一个数字为initialValues:
type UseFormProps<T extends InitialValues> = {
initialValues: T
}
现在打字稿会自动选择T,这正是我们所需要的:如果initialValues是{ foo: 1, bar: 'str' },那么它将是{ foo: number, bar: string },仅此而已。
最后去FormValues:
type FormValues<T extends InitialValues> = {
[x in keyof T]: FormValue<x, T[x]>
}
现在FormValues 将不仅是可索引的,而且将完全包含T 包含的属性,而且T[x] 不会像T[keyof T] 这样的联合,x 的每个值都会有所不同所以对于每个属性。基本上就是这样,现在它应该可以按预期工作了。您只需要更改transformInitialValues 中的某些内容,因为如果您将空对象分配给FormValues<whatever>,打字稿现在会报错