我在下面的链接中有一个最小的可重复的问题示例:

import React, { useState } from 'react';

type InputValue = string[] | string;

interface InputProps<T extends InputValue> {
    value: T;
}

// -------------------------------------------------------------------------------------------------
// TEXT INPUT
// -------------------------------------------------------------------------------------------------

const TextInput = ({ value = '' }: InputProps<string>): React.ReactElement => {
    return <input value={value} />;
};

// -------------------------------------------------------------------------------------------------
// FORM FIELD
// -------------------------------------------------------------------------------------------------

interface FormFieldProps<T extends InputValue> {
    render: (props: InputProps<T>) => React.ReactElement;
    value: T;
}

const FormField = <T extends InputValue>({
    render,
    value,
}: FormFieldProps<T>): React.ReactElement => (
    <div>
        {render({ value })}
    </div>
);

// -------------------------------------------------------------------------------------------------
// FORM
// -------------------------------------------------------------------------------------------------

interface FieldPropsReturn<T> {
    value: T[keyof T];
}

interface UseFormReturn<T> {
    fieldProps: (name: keyof T) => FieldPropsReturn<T>;
}

const useForm = <T extends object>(): UseFormReturn<T> => {
    const [formData] = useState<T>({} as T);

    const fieldProps = (name: keyof T): FieldPropsReturn<T> => ({
        value: formData[name],
    });

    return {
        fieldProps
    };
};

// -------------------------------------------------------------------------------------------------
// INDEX
// -------------------------------------------------------------------------------------------------

interface IndexFormFields {
    fruits: string[];
    name: string;
}

const Index = (): React.ReactElement => {
    const { fieldProps } = useForm<IndexFormFields>();

    return (
        <FormField
            {...fieldProps('name')}
            render={(props): React.ReactElement => <TextInput {...props} />}
        />
    );
};

export default Index;

Playground link

基本上,我正在构建一些表单助手,包括一个FormField,用于呈现表单组件.我希望这FormField个渲染函数从传递给fieldProps的键推断出值类型,但目前它在TextInput组件上返回以下错误:

Type '{ value: string | string[]; }' is not assignable to type 'InputProps<string>'.
  Types of property 'value' are incompatible.
    Type 'string | string[]' is not assignable to type 'string'.
      Type 'string[]' is not assignable to type 'string'.

根据IndexFormFields接口,对于FormFieldfieldProps为"name"的渲染函数是否有任何方式可以传递string的值类型,而对于fieldProps为"fruits"的渲染函数是否可以传递string[]的值类型?

推荐答案

fieldProps中添加一个通用答案,类似于this答案:


    const fieldProps = <Name extends keyof T>(name: Name): FieldPropsReturn<T, Name> => ({
        value: formData[name],
    });

您还需要更新界面以反映这一点:

interface FieldPropsReturn<T, K extends keyof T = keyof T> {
    value: T[K];
}

useForm上的返回类型也是不需要的,但如果必须的话,还必须在那里更改fieldProps的类型.

现在,当您使用组件时,不会出现错误.如果你用错了,就会出错.

Playground

Typescript相关问答推荐

接口DOMRouter选项未输出

为什么在TypScript中将类型守护的返回类型写成This is(

具有条件通用props 的react 类型脚本组件错误地推断类型

在Angular中,如何在文件上传后清除文件上传文本框

node—redis:如何在redis timeSeries上查询argmin?

无法正确推断嵌套泛型?

有条件地删除区分的联合类型中的属性的可选属性

如何解决类型T不能用于索引类型{ A:typeof A; B:typeof B;. }'

如何在深度嵌套的Reaction路由对象中隐藏父级?

为什么ESLint会抱怨函数调用返回的隐式`any`?

在正常函数内部调用异步函数

在抽象类属性定义中扩展泛型类型

使用Type脚本更新对象属性

重写返回任何

如何以类型安全的方式指定键的常量列表,并从该列表派生所挑选的接口?

换行TypeScript';s具有泛型类型的推断数据类型

如何在TypeScript中将元组与泛型一起使用?

如何通过nx找到所有受影响的项目?

基于参数的 TS 返回类型

我可以在 Typescript 中重用函数声明吗?