メインコンテンツスキップ

クラスコンポーネント

TypeScript の中では、React.Component はジェネリック型(別名 React.Component<PropType, StateType>)なので、(オプションの)小道具とステートの型の parameta を指定する必要があります。

type MyProps = {
// using `interface` is also ok
message: string;
};
type MyState = {
count: number; // like this
};
class App extends React.Component<MyProps, MyState> {
state: MyState = {
// optional second annotation for better type inference
count: 0,
};
render() {
return (
<div>
{this.props.message} {this.state.count}
</div>
);
}
}

TypeScript のプレイグラウンドで確認

これらの型/インターフェースを再利用のためにエクスポート/インポート/拡張できます。

state を 2 回アノテーションする理由

state のクラスプロパティを明示的にアノテーションする必要はありませんが、this.state へのアクセス時とステートの初期化時の型の推論が容易になります。

これらは 2 つの異なる動作を行うからです。2 番目のジェネリック型パラメータにより、this.setState() は正しく機能します。このメソッドは基本クラスから派生していますが、コンポーネント内で state を初期化すると基本的な実装がオーバーライドされるため、コンパイラに実際には異なることは何も行っていません。ということを確認する必要があります。

@ferdaber がここにコメント.

readonly は必要ありません

サンプルコードには、小道具とステートを不変にするために readonly が組み込まれていることがよくあります。

type MyProps = {
readonly message: string;
};
type MyState = {
readonly count: number;
};

これは React.Component<P,S> がすでに不変としてマークしているため必要ありません。(PR と議論をご覧ください!

クラスメソッド:通常どおり実行しますが、関数に引数がある場合は、それらも型指定する必要があることを忘れないでください。

class App extends React.Component<{ message: string }, { count: number }> {
state = { count: 0 };
render() {
return (
<div onClick={() => this.increment(1)}>
{this.props.message} {this.state.count}
</div>
);
}
increment = (amt: number) => {
// like this
this.setState((state) => ({
count: state.count + amt,
}));
};
}

TypeScript のプレイグラウンドで確認

クラスプロパティ:後で使用するクラスプロパティを宣言する必要がある場合は、state のように宣言しますが、代入はしません。

class App extends React.Component<{
message: string;
}> {
pointer: number; // like this
componentDidMount() {
this.pointer = 3;
}
render() {
return (
<div>
{this.props.message} and {this.pointer}
</div>
);
}
}

TypeScript のプレイグラウンドで確認

追加すべきことがありますか?問題を送信.

getDerivedStateFromProps の型指定

getDerivedStateFromProps の使用を開始する前に、ドキュメンテーションYou Probably Don't Need Derived State をご覧ください。派生ステートは、メモ化のセットアップにも役立つ可能性のあるフックを使用して実装できます。

以下に getDerivedStateFromProps をアノテーションする方法をいくつか示します。

  1. 派生ステートを明示的に型指定し、getDerivedStateFromProps からの戻り値がそれに準拠していることを確認する場合。
class Comp extends React.Component<Props, State> {
static getDerivedStateFromProps(
props: Props,
state: State
): Partial<State> | null {
//
}
}
  1. 関数の戻り値をステートを決定させる場合。
class Comp extends React.Component<
Props,
ReturnType<typeof Comp["getDerivedStateFromProps"]>
> {
static getDerivedStateFromProps(props: Props) {}
}
  1. 他のステートフィールドやメモ化による派生ステートが必要な場合。
type CustomValue = any;
interface Props {
propA: CustomValue;
}
interface DefinedState {
otherStateField: string;
}
type State = DefinedState & ReturnType<typeof transformPropsToState>;
function transformPropsToState(props: Props) {
return {
savedPropA: props.propA, // save for memoization
derivedState: props.propA,
};
}
class Comp extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
otherStateField: "123",
...transformPropsToState(props),
};
}
static getDerivedStateFromProps(props: Props, state: State) {
if (isEqual(props.propA, state.savedPropA)) return null;
return transformPropsToState(props);
}
}

TypeScript のプレイグラウンドで確認