打字稿泛型类型 - 类型“keyof T1”不能用于索引类型

时间:2021-03-04 08:08:08

标签: javascript typescript

我有验证表单的函数,我希望该函数位于一个单独的文件中,但我有 validationRequirements[fieldName] 的类型问题,我收到错误 Type 'keyof T1' cannot be used to index type '{ name: (value: string) => boolean; }'.

这是我的验证要求:

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

createValidationObj 接口:

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

这里我调用一个函数来更新验证对象,我将 validationI 作为打字稿参数传递,然后我将它用作通用:

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

这是验证函数,我想单独使用该函数:

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,
    },
})

链接到示例:Example

1 个答案:

答案 0 :(得分:1)

问题

考虑这个代码。 Parent 类型的对象中的任何字段都可以分配给 Child 类型的对象(只要它们的类型匹配)。这是因为 Parent 有键 "a" | "b"。因此,当然,parentObject 具有 childObject 具有的键,但反之亦然,因为 parentObject 缺少 c 中的键 childObject

所以,简而言之,我们要为其分配字段的对象的键必须是我们要分配给的对象的键的子集。

{} 类型的键是空集,因此函数 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

因此,在问题中,在函数 createValidationObj 中,fieldName 具有键 - keyof {},它绝对不是 validationRequirements(“名称”)的键的子集。所以错误。

解决方案

如果它不违反您的要求,请完全删除 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