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

如何为React Exercise组件的exerciseComponentProps添加类型约束?

问题:为Exercise组件的exerciseComponentProps添加类型约束并传递onMarkAsCompleted

我正在开发一个带练习功能的网站,每个练习对应不同的React组件。我用Exercise组件作为统一包裹层,提供标题、完成日期等基础样式,具体练习组件从外部传入:

const exercises = [
  <Exercise
    key={1}
    numberInLesson={1}
    title={"Typing the alphabet"}
    ExerciseComponent={TypingTheAlphabet}
    exerciseComponentProps={{
       ...some props to pass to TypingTheAlphabet
    }}
  />,
  <Exercise
    key={2}
    numberInLesson={2}
    title={"Which letter? - Vowels"}
    ExerciseComponent={WhichLetter}
    exerciseComponentProps={{
      ...some props to pass to WhichLetter
    }}
  />
]

需要实现两个需求:

  • 为Exercise组件的exerciseComponentProps添加类型约束,确保传入的props仅对应指定ExerciseComponent的有效props
  • 将Exercise组件的onMarkAsCompleted属性传递给内部练习组件

以下是当前Exercise组件的Props接口及实现代码,请问如何正确标注exerciseComponentProps的类型?

export interface ExerciseComponentProps {
  onMarkAsCompleted: () => void;
}

export type ExerciseComponentType = ComponentType<ExerciseComponentProps>;

export interface CommonExerciseProps<C extends ExerciseComponentType> {
  id: string;
  numberInLesson: number;
  title: string;
  ExerciseComponent: C;
  exerciseComponentProps: // how can I type this?
}

const Exercise: React.FC<CommonExerciseProps<any>> = (
  props
) => {
  const [exerciseCompletionDate, setExerciseCompletionDate] = 
    useState<Date | null>(null);
  const {
    numberInLesson,
    title,
    ExerciseComponent,
    exerciseComponentProps,
  } = props;

  return (
    <div
      className="w3-padding-small"
      style={exerciseCompletionDate ? { border: "1px solid green" } : {}}
    >
      <h3>
        Exercise {numberInLesson}:
        <br />
        {title}
      </h3>
      {exerciseCompletionDate && (
        <small>
          Completed on {exerciseCompletionDate.toISOString().substring(0, 10)}
        </small>
      )}

      <ExerciseComponent
        onMarkAsCompleted={
          !exerciseCompletionDate
            ? () => setExerciseCompletionDate(new Date())
            : () => {}
        }
        {...exerciseComponentProps}
      />
    </div>
  );
};

export default Exercise;

解决方案

1. 为exerciseComponentProps添加精准类型约束

利用TypeScript内置的ComponentProps工具类型提取目标组件的props类型,再通过Omit排除掉由Exercise组件内部提供的onMarkAsCompleted属性,修改CommonExerciseProps接口如下:

import React, { ComponentType, ComponentProps } from 'react';

export interface ExerciseComponentProps {
  onMarkAsCompleted: () => void;
}

export type ExerciseComponentType = ComponentType<ExerciseComponentProps>;

export interface CommonExerciseProps<C extends ExerciseComponentType> {
  id: string;
  numberInLesson: number;
  title: string;
  ExerciseComponent: C;
  // 提取C的props类型,排除内部已处理的onMarkAsCompleted
  exerciseComponentProps: Omit<ComponentProps<C>, 'onMarkAsCompleted'>;
}

2. 调整Exercise组件的泛型定义

将组件从React.FC<CommonExerciseProps<any>>改为泛型组件,避免使用any丢失类型校验:

const Exercise = <C extends ExerciseComponentType>(
  props: CommonExerciseProps<C>
) => {
  const [exerciseCompletionDate, setExerciseCompletionDate] = 
    useState<Date | null>(null);
  const {
    numberInLesson,
    title,
    ExerciseComponent,
    exerciseComponentProps,
  } = props;

  return (
    <div
      className="w3-padding-small"
      style={exerciseCompletionDate ? { border: "1px solid green" } : {}}
    >
      <h3>
        Exercise {numberInLesson}:
        <br />
        {title}
      </h3>
      {exerciseCompletionDate && (
        <small>
          Completed on {exerciseCompletionDate.toISOString().substring(0, 10)}
        </small>
      )}

      <ExerciseComponent
        onMarkAsCompleted={
          !exerciseCompletionDate
            ? () => setExerciseCompletionDate(new Date())
            : () => {}
        }
        {...exerciseComponentProps}
      />
    </div>
  );
};

export default Exercise;

效果说明

  • 外部传入exerciseComponentProps时,TypeScript会自动校验是否匹配对应ExerciseComponent的props要求,多传、少传或类型不匹配都会触发报错
  • onMarkAsCompleted由Exercise组件内部生成并注入,外部无需传入,类型约束也会禁止外部传递该属性
  • 所有练习组件都必须符合ExerciseComponentType类型(即接收onMarkAsCompleted props),确保回调能正确传递

内容的提问来源于stack exchange,提问作者pg-robban

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 06:27:25