web-dev-qa-db-ja.com

Reactコンポーネントの子はtypescriptでタイプチェックします

シナリオは次のとおりです。

カスタムコンポーネントがあります:

class MyComponent extends React.Component {
  render () {
    return (
      <SuperComponent>
        <SubComponent1 />  // <- valid child
      </SuperComponent>
    )
}

class MyComponent extends React.Component {
  render () {
    return (
      <SuperComponent>
        <SubComponent2 />  // <- No! It's not right shape
      </SuperComponent>
    )
}

参照されるSuperComponentとSubComponent1は次のとおりです。

interface superPropsType = {
  children: ReactElement<subPropsType1>
}
class SuperComponent extends React.Component<superPropsType> { ... }


interface subPropsType1 = {
  name: string
}
class SubComponent1 extends React.Component<subPropsType1> { ... }


interface subPropsType2 = {
  title: string
}
class SubComponent2 extends React.Component<subPropsType2> { ... }

SubComponent1をSuperComponentの唯一の有効な子にしたい、つまり、<SubComponent2 />またはその他のタイプを<SuperComponent>の子として配置した場合にTypeScriptがエラーをスローできるようにしたい。

TypeScriptはの子がReactElementのタイプである必要があることだけをチェックしているようですが、tsはその子(subPropsType1)の小道具の形状をチェックしません。つまり、文字列または数値をSuperComponentの子として配置した場合です。 、tsは、型の要件が満たされていないことを訴えますが、ここにjsxタグ(ReactElementにトランスパイルされます)を配置すると、tsはサイレントになります

何か案が ?また、ここに投稿するために設定が必要な場合は、遠慮なく質問してください

アイデアと解決策に本当に感謝します

7
Noah

TypeScript 3.1以降、すべてのJSX要素はJSX.Elementタイプを持つようにハードコードされているため、特定のJSX要素を受け入れる方法はなく、他の要素を受け入れる方法はありません。この種のチェックが必要な場合は、JSX構文を放棄し、React.createElementをラップするが、コンポーネントタイプごとに異なる要素タイプを返す独自の要素ファクトリ関数を定義し、そのファクトリ関数への呼び出しを手動で書き込む必要があります。

TypeScriptがファクトリ関数の実際の戻り値の型に基づいてJSX要素に型を割り当てるための オープンな提案 があります。これはTypeScript 3.2(2018年11月下旬にリリース予定)と同時に実装される可能性があります。特定のコンポーネントタイプに対して。それが実装されると、React.createElementをラップする独自のファクトリ関数を定義し、それをjsxFactoryコンパイラオプションで指定できるようになり、追加の型情報を取得できます。または、機能を気にしないプロジェクトに悪影響を与えることなく実行できる場合は、@types/reactが変更されてReact.createElementがより豊富な型情報を提供するようになるかもしれません。私たちは待って見る必要があります。

4
Matt McCutchen

私はおそらくSuperPropsType.childrenを次のように宣言します。

children: React.ReactElement<SubPropsType1> | React.ReactElement<SubPropsType1>[];

単一の子と複数の子の両方を持つ可能性を説明するため。

いずれにせよ、すでに指摘したように、それは期待どおりに機能しません。

代わりにできることは、小道具を宣言することです。たとえば、subComponentProps: SubPropsType1[]を宣言して、JSXではなくSubComponent1を作成し、SuperComponent内にレンダリングするために必要な小道具を渡します。

interface SuperPropsType {
  children?: never;
  subComponentProps?: SubPropsType1[];
}

...

const SuperComponent: React.FC<SuperPropsType> = ({ subComponentProps }) => {
  return (
    ...

    { subComponentProps.map(props => <SubComponent1 key={ ... } { ...props } />) }

    ...
  );
};
0
Danziger