简体   繁体   中英

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; }'. 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:

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:

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:

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). This is because Parent has keys "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 .

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.

The keys of type {} is an empty set, therefore, the error in 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"). So the error.

Solution

If it does not violate your requirements, remove T1 at all.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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