You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript与React中用泛型根据组件Prop值定义另一Prop类型

实现基于Input类型的精确Options类型推断

要实现根据type参数自动推断options类型,同时禁止textarea类型传递options,可以通过可辨识联合类型(Discriminated Union)或泛型条件类型两种方式实现,以下是具体方案:

先定义基础类型

首先补充你需要的各选项类型示例(根据实际业务调整):

type SelectOption = { label: string; value: string };
type RadioOption = { label: string; value: string; disabled?: boolean };
type CheckboxOption = { label: string; value: string; checked?: boolean };

// 输入类型定义
type InputType = 'text' | 'select' | 'radioGroup' | 'checkboxGroup' | 'textarea';

// 类型映射表:关联Input类型与对应的Options类型
type InputOptionsMapping = {
  text: SelectOption[];
  select: SelectOption[];
  radioGroup: RadioOption[];
  checkboxGroup: CheckboxOption[];
  textarea: never; // textarea禁止传options,用never标记
};

方案一:使用可辨识联合类型(推荐)

这种方式无需泛型,TypeScript会自动根据type字段完成类型推断,代码更简洁直观:

1. 定义组件Props类型

// 公共属性(所有Input类型共享的props)
type BaseInputProps = {
  name: string;
  placeholder?: string;
  // 其他公共属性...
};

// 生成可辨识联合类型的Props:每个type对应专属的结构
type InputProps = {
  [K in keyof InputOptionsMapping]: BaseInputProps & {
    type: K;
  } & (InputOptionsMapping[K] extends never 
    ? {} // textarea类型不包含options属性
    : { options?: InputOptionsMapping[K] }) // 其他类型对应可选的options
}[keyof InputOptionsMapping];

2. 实现组件

import React from 'react';

const Input: React.FC<InputProps> = (props) => {
  switch (props.type) {
    case 'text':
      // 此处props.options自动推断为SelectOption[] | undefined
      return <input type="text" {...props} />;
    case 'select':
      return (
        <select name={props.name} placeholder={props.placeholder}>
          {props.options?.map(opt => (
            <option key={opt.value} value={opt.value}>{opt.label}</option>
          ))}
        </select>
      );
    case 'radioGroup':
      return (
        <div>
          {props.options?.map(opt => (
            <label key={opt.value}>
              <input type="radio" name={props.name} value={opt.value} disabled={opt.disabled} />
              {opt.label}
            </label>
          ))}
        </div>
      );
    case 'checkboxGroup':
      return (
        <div>
          {props.options?.map(opt => (
            <label key={opt.value}>
              <input type="checkbox" name={props.name} value={opt.value} checked={opt.checked} />
              {opt.label}
            </label>
          ))}
        </div>
      );
    case 'textarea':
      // 此处props不存在options属性,强行传递会触发TypeScript报错
      return <textarea {...props} />;
    default:
      throw new Error(`不支持的Input类型:${(props as never).type}`);
  }
};

使用示例

// ✅ 正确:text类型的options自动推断为SelectOption[]
<Input type="text" name="username" options={[{ label: '测试', value: 'test' }]} />

// ❌ 错误:textarea类型禁止传递options,TypeScript会直接报错
<Input type="textarea" name="desc" options={[]} />

// ✅ 正确:checkboxGroup类型的options自动推断为CheckboxOption[]
<Input type="checkboxGroup" name="hobbies" options={[{ label: '篮球', value: 'basketball', checked: true }]} />

方案二:改进泛型接口定义

如果更倾向于使用泛型,可以通过条件类型让options类型严格绑定type参数:

1. 定义泛型Props接口

type BaseInputProps = {
  name: string;
  placeholder?: string;
  // 其他公共属性...
};

interface InputProps<TInput extends InputType> extends BaseInputProps {
  type: TInput;
  // 条件类型:如果是textarea(映射值为never),则options为never(禁止传递);否则为对应类型
  options?: InputOptionsMapping[TInput] extends never ? never : InputOptionsMapping[TInput];
}

2. 实现泛型组件

import React from 'react';

function Input<TInput extends InputType>(props: InputProps<TInput>) {
  switch (props.type) {
    case 'text':
      return <input type="text" {...props} />;
    // ...其他case逻辑同方案一
    case 'textarea':
      return <textarea {...props} />;
    default:
      throw new Error(`不支持的Input类型:${props.type}`);
  }
}

为什么之前的方案失效?

你之前直接在泛型接口中使用options?: InputOptionsMapping[TInput],但如果组件定义为普通的React.FC<Input<TInput>>,TypeScript无法自动推断具体的TInput类型,会将options推断为所有映射值的联合类型。而通过可辨识联合类型或泛型函数,TypeScript能根据传入的type参数精确锁定对应的TInput,从而得到正确的options类型。

内容的提问来源于stack exchange,提问作者thatVar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 16:05:33