简体   繁体   English

Typescript 泛型类型 - 类型“keyof T1”不能用于索引类型

[英]Typescript generic type - Type 'keyof T1' cannot be used to index type

I have functions to validate forms, I want the function to be in a separate file, but I have a type problem for validationRequirements[fieldName] i getting error Type 'keyof T1' cannot be used to index type '{ name: (value: string) => boolean; }'.我有验证 forms 的功能,我希望 function 位于单独的文件中,但我有一个类型问题, validationRequirements[fieldName]我收到错误Type 'keyof T1' cannot be used to index type '{ name: (value: string) => boolean; }'. Type 'keyof T1' cannot be used to index type '{ name: (value: string) => boolean; }'.

Here is my validations requirements:这是我的验证要求:

const validationRequirements = {
    name: (value: string) => false, //mock
}

Interface for createValidationObj: createValidationObj 的接口:

interface CreateValidationObjI<T1> {
    validation: T1
    fieldName: keyof T1
    value: string
}

Here I call a function to update the validation object, I pass validationI as typescript argument then i use it as generic:在这里,我调用 function 来更新验证 object,我将validationI I 作为 typescript 参数传递,然后我将其用作通用参数:

const onChangeValidation = ({ value, fieldName }: { value: string; fieldName: keyof typeof validation }) => {
    const validationObj = createValidationObj<validationI>({ validation, fieldName, value })
}

Here is the validation function, I want that function in separate:这是验证 function,我希望 function 分开:

const createValidationObj = <T1 extends {}>({ validation, fieldName, value }: CreateValidationObjI<T1>) => ({
    ...validation,
    [fieldName]: {
        ...validation[fieldName],
        isValid: validationRequirements[fieldName](value), <-- Type 'keyof T1' cannot be used to index type '{ name: (value: string) => boolean; }'.
        isTouched: true,
    },
})

Link to example: Example示例链接: 示例

Problem问题

Consider this code.考虑这段代码。 Any field from object of type Parent is assignable to object of type Child (as soon as their type matches). object 类型的Parent中的任何字段都可以分配给Child类型的 object(只要它们的类型匹配)。 This is because Parent has keys "a" | "b"这是因为Parent有键"a" | "b" "a" | "b" . "a" | "b" So, definitely, parentObject has keys that childObject has but vice-versa is not true as parentObject is missing key c from the childObject .因此,当然, parentObject具有childObject具有的键,但反之亦然,因为parentObject缺少来自childObject c

So, in short, the keys of the object whose fields we are assigning must be subset of keys the object to which we are assigning.因此,简而言之,我们分配的字段的 object 的键必须是我们分配的 object 的键的子集。

The keys of type {} is an empty set, therefore, the error in function f3 . {}类型的键是一个空集,因此 function f3中的错误。

interface Parent {
    a: string
    b: string
}

interface Child {
    a: string
    b: string
    c: string
}

const parentObject: Parent = {
    a: "abc",
    b: "string"
}

const childObject: Child = {
    a: "abc",
    b: "string",
    c: "string"
}

type KeysOfParent = keyof Parent // "a" | "b"
type KeysOfChild = keyof Child // "a" | "b" | "c"

function f(field: keyof Parent) {
    childObject[field] = "abc" // OK
}

function f2(field: keyof Child) {
    parentObject[field] = "abc" // ERROR
}

function f3<T extends {}>(field: keyof T) {
    parentObject[field] = "abc" // ERROR
}

Playground 操场

So, in the question, in function createValidationObj , fieldName has keys - keyof {} which is definitely not asubset of keys of validationRequirements ("name").因此,在问题中,在 function createValidationObj中, fieldName有键 - keyof {}这绝对不是validationRequirements键的子集(“名称”)。 So the error.所以错误。

Solution解决方案

If it does not violate your requirements, remove T1 at all.如果它不违反您的要求,请完全删除T1

interface validationI {
    name: {
        isValid: boolean
        isTouched: boolean
        errorMsg: string
    },
    field2: {
        isValid: boolean
        isTouched: boolean
        errorMsg: string
    },
}

const validation: validationI = {
    name: {
        isValid: false,
        isTouched: false,
        errorMsg: "Min 3 chars",
    },
    field2: {
        isValid: false,
        isTouched: false,
        errorMsg: "Min 3 chars",
    },
}
type X = keyof typeof validation

const validationRequirements = {
    name: (value: string) => false, //mock
    field2: (value: string) => false, //mock
}

interface CreateValidationObjI<T1 extends validationI> {
    validation: T1
    fieldName: keyof T1
    value: string
}

const createValidationObj = ({validation, fieldName, value}: CreateValidationObjI<validationI>) => ({
    ...validation,
    [fieldName]: {
        ...validation[fieldName],
        isValid: validationRequirements[fieldName](value),
        isTouched: true,
    }
})

const onChangeValidation = ({ value, fieldName }: { value: string; fieldName: keyof typeof validation }) => {
    const validationObj = createValidationObj({ validation, fieldName, value })
}

Playground 操场

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM