0Pricing
Frontend Academy · レッスン

ReactとTypeScript:FC・ジェネリクス・フック

ジェネリックなpropsでReactコンポーネントに型を付け、useStateとuseRefに明示的な型を付け、タプルを返すカスタムフックにも型を付けます。

「ReactとTypeScript:FC・ジェネリクス・フック」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。

コンポーネントの型付け

現代のReactでは、interfaceでpropsの型を定義し、通常の関数を使用します。React.FCも存在しますが、暗黙的なchildrenやジェネリックの非対応といった理由から、現在は推奨されていません。

// Recommended:
interface ButtonProps {
  label: string;
  onClick: () => void;
  disabled?: boolean;
}

function Button({ label, onClick, disabled }: ButtonProps) {
  return <button onClick={onClick} disabled={disabled}>{label}</button>;
}

childrenの型付け

描画可能な子要素にはReact.ReactNodeを使用します。

interface CardProps {
  title: string;
  children: React.ReactNode;
}

function Card({ title, children }: CardProps) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

useStateの型付け

useStateは通常、初期値から型を推論します。初期値がnullの場合や、取り得る型全体を表していない場合は、明示的に型を指定します。

const [count, setCount] = useState(0);              // number
const [name, setName] = useState('');                // string

const [user, setUser] = useState<User | null>(null); // explicit
const [items, setItems] = useState<Item[]>([]);      // explicit array type

useRefの型付け

形式は2つあります。DOM要素へのref(nullで初期化)と、可変コンテナーです。

const inputRef = useRef<HTMLInputElement>(null);
const timerRef = useRef<number | null>(null);

useEffect(() => {
  inputRef.current?.focus();
  timerRef.current = window.setInterval(tick, 1000);
  return () => clearInterval(timerRef.current!);
}, []);

イベントハンドラーの型付け

Reactの合成イベント型を使用します。

function Form() {
  function onSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
  }
  function onChange(e: React.ChangeEvent<HTMLInputElement>) {
    setValue(e.target.value);
  }
  function onClick(e: React.MouseEvent<HTMLButtonElement>) {
    /* ... */
  }
  return <form onSubmit={onSubmit}>...</form>;
}

ジェネリックコンポーネント

コンポーネントをジェネリックにできます。TypeScriptは呼び出し箇所から型パラメーターを推論します。

interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
  keyOf: (item: T) => string | number;
}

function List<T>({ items, renderItem, keyOf }: ListProps<T>) {
  return <ul>{items.map(i => <li key={keyOf(i)}>{renderItem(i)}</li>)}</ul>;
}

<List<User>
  items={users}
  renderItem={u => u.name}
  keyOf={u => u.id}
/>

カスタムフックの型付け

カスタムフックは関数なので、ほかの関数と同じように型付けします。配列型への拡大解釈を避けるため、タプルを返す場合は明示的なアノテーションが必要です。

function useToggle(initial = false): [boolean, () => void] {
  const [value, setValue] = useState(initial);
  const toggle = () => setValue(v => !v);
  return [value, toggle]; // tuple — annotation makes this stable
}

const [isOpen, toggle] = useToggle();

Contextの型付け

createContextには、提供する値と同じ型の初期値が必要です。non-null assertionまたはデフォルトオブジェクトを使用します。

interface AuthContextValue {
  user: User | null;
  signIn: (email: string, pw: string) => Promise<void>;
  signOut: () => void;
}

const AuthContext = createContext<AuthContextValue | null>(null);

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be inside AuthProvider');
  return ctx;
}

useReducerの型付け

状態とアクションのユニオンを明示的に型付けします。

type State = { count: number };
type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'set'; value: number };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    case 'set':       return { count: action.value };
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0 });

React.FCを避ける

React.FCは次第に使われなくなっています。childrenを暗黙的に追加し、ジェネリックコンポーネントを適切にサポートせず、一部の最適化を妨げるためです。型付けしたpropsを持つ通常の関数コンポーネントを推奨します。

ComponentPropsWithoutRefユーティリティ

ネイティブ要素のpropsを継承する(buttonやinputを拡張する)には、ComponentPropsWithoutRefを使用します。

type ButtonProps = React.ComponentPropsWithoutRef<'button'> & {
  variant?: 'primary' | 'secondary';
};

function Button({ variant = 'primary', ...rest }: ButtonProps) {
  return <button className={`btn ${variant}`} {...rest} />;
}

クイックチェック

通常の型付き関数コンポーネントを使うほうがReact.FCより一般的に推奨されるのはなぜですか?

復習:TypeScript + React

propsはインターフェースで型付けし、React.FCより通常の関数を優先します。childrenにはReact.ReactNodeを使用します。useStateは型を推論できることが多いですが、nullや空の配列の場合は型注釈を付けます。DOM要素にはuseRefを使用します。イベントハンドラーにはReactのイベント型を使用します。再利用可能なリストやフォームにはジェネリックコンポーネントを使用します。カスタムフックがタプルを返す場合は型注釈が必要です。ネイティブ要素を拡張するにはComponentPropsWithoutRefを使用します。

よくある質問

「ReactとTypeScript:FC・ジェネリクス・フック」レッスンは無料ですか?

はい。「ReactとTypeScript:FC・ジェネリクス・フック」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。

「ReactとTypeScript:FC・ジェネリクス・フック」で何を学びますか?

ジェネリックなpropsでReactコンポーネントに型を付け、useStateとuseRefに明示的な型を付け、タプルを返すカスタムフックにも型を付けます。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Frontend Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「ReactとTypeScript:FC・ジェネリクス・フック」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このFrontend Academyレッスンでコードを書いて実行できますか?

はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. テンプレートリテラル型
  2. デコレーターとメタデータ
  3. ReactとTypeScript:FC・ジェネリクス・フック
  4. Strictモードとanyの排除
← Frontend Academyに戻る