【问题标题】:Passing implementations of generic types to React component props将泛型类型的实现传递给 React 组件道具
【发布时间】:2019-01-24 14:05:10
【问题描述】:

我正在开发一个 TypeScript/React 项目,我们正在为多步骤流程构建一个通用的“向导”组件。该向导是一个包装器,它采用一组“面板”组件属性,并通过 IWizardPanelProps 接口向每个属性公开导航逻辑。

Wizard组件和面板界面的实现如下:

export interface IWizardPanelProps {
  changePanel: (increment: number) => void;
}

export class WizardPanel<T> extends React.Component<IWizardPanelProps & T>{
  constructor(props: IWizardPanelProps & T) {
    super(props);
  }
}

interface IWizardProps {
  panelComponents: (typeof WizardPanel)[],
  showControls?: boolean // Hidden by default - assumes panels themselves handle pagination
}

interface IWizardState {
  panelIndex: number
}

export class Wizard extends React.Component<IWizardProps, IWizardState> {
  constructor(props: IWizardProps) {
    super(props);

    this.state = {
      panelIndex: 0
    }
  }

  changePanel = (increment: number) => {
    const newIndex = this.state.panelIndex + increment;

    this.setState({ panelIndex: newIndex });
  };

  render() {
    const { panelComponents, showControls } = this.props;

    return (
      <div>
        <p><strong>Ye olde Wizard Component! (This is a placeholder, but the functionality is mostly there)</strong></p>
        {panelComponents.map((Panel, key) => (
          <div className={key === this.state.panelIndex ? undefined : 'hidden'} key={key}>{<Panel {...this.props} changePanel={this.changePanel}></Panel>}</div>
        ))}
        {showControls && <div>
            <button disabled={this.state.panelIndex === 0} onClick={() => this.changePanel(-1)}>
            Previous
          </button>
          <button disabled={this.state.panelIndex === panelComponents.length - 1} onClick={() => this.changePanel(1)}>
            Next
          </button>
        </div>}
      </div>
    );  
  }
}

然后当我们创建一个面板组件时,我们这样做:

interface IMyPanelProps {
  ...
}


export class MyPanel extends WizardPanel<IMyPanelProps> {
  constructor(props: IWizardPanelProps & IMyPanelProps) {
    super(props);
  }
  render() {
    ...
  }
  ...
}

到目前为止还不错吧?

但是当我们去实现这样的向导时:

<Wizard panelComponents={[ MyPanel ]}></Wizard>

我们得到以下错误:

类型 '(typeof MyPanel)[]' 不可分配给类型 '(typeof 向导面板)[]'。

类型 'typeof MyPanel' 不可分配给类型 'typeof 向导面板'。

类型“MyPanel”不可分配给类型“WizardPanel”。

属性“props”的类型不兼容。

Type 'Readonly & Readonly' 不可分配给类型 'Readonly & Readonly'。

Type 'Readonly & Readonly ' 不可分配给类型'Readonly '。

什么给了?似乎可以归结为最后一行:

Readonly&lt;{ children?: ReactNode; }&gt; &amp; Readonly&lt; IWizardPanelProps &amp; IMyPanelProps&gt;' is not assignable to type 'Readonly&lt; IWizardPanelProps &amp; T&gt;

但我不明白我做错了什么。我们如何在 propComponents 的 IWizardProps 声明中缺少 Readonly&lt;{ children?: ReactNode; }&gt;??

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    您可以使用React.ComponentType 类型。这是定义组件类型的预期方式。

    interface IWizardProps {
        panelComponents: React.ComponentType<IWizardPanelProps>)[],
        showControls?: boolean 
    }
    

    问题是WizardPanel 是通用的,而分配的类不是,这会导致类型之间的不兼容。例如,这也可以:

    export class BasicWizardPanel extends WizardPanel<{}>{}
    
    interface IWizardProps {
        panelComponents: (typeof BasicWizardPanel)[],
        showControls?: boolean // Hidden by default - assumes panels themselves handle pagination
    }
    

    【讨论】:

    • 我该死。谢谢!
    • 这正是我解决类似问题所需要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-12
    • 1970-01-01
    相关资源
    最近更新 更多