React 与 TypeScript 类型进阶:用泛型组件与可辨识联合把 props 严丝合缝

test12026-10-2916 次阅读

为什么要在组件上做类型收敛

很多团队把组件的 props 写成宽松的 any 或大而全的可选字段,结果运行时才暴露“少传了一个字段”或“传错了类型”的问题。React 配合 TypeScript 可以把这一类错误前移到编译期。本文用两个具体手段:泛型组件和可辨识联合(discriminated union),把 props 的类型边界收紧。

一、泛型组件:让列表组件吃得下任意数据

写一个通用列表组件,数据项类型由调用方决定,组件内部只关心“怎么渲染每一项”。用泛型参数把数据形状和渲染函数绑定起来。

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

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

// 调用时类型被推导出来,user 一定是 { id: number; name: string }
const users = [{ id: 1, name: "Ada" }];
<GenericList items={users} keyOf={(u) => u.id} renderItem={(u) => u.name} />;

这里 T 由 users 推导为 { id: number; name: string },如果 renderItem 里写成 u.age 就会在编译期报错,而不是等产品上线后白屏。

二、可辨识联合:让组件的“模式分支”穷尽且类型安全

组件经常需要根据 mode 渲染不同形态。把 mode 和对应字段放进可辨识联合,配合 switch 的穷尽检查,漏掉一种情况编译器会直接提醒你。

type ButtonProps =
  | { variant: "solid"; color: string }
  | { variant: "ghost"; borderColor: string }
  | { variant: "link"; href: string };

function Button(props: ButtonProps) {
  switch (props.variant) {
    case "solid":
      return <button style={{ background: props.color }} />;
    case "ghost":
      return <button style={{ borderColor: props.borderColor }} />;
    case "link":
      return <a href={props.href}>链接</a>;
    default: {
      const _exhaustive: never = props;
      return _exhaustive;
    }
  }
}

switch 的 default 分支把 props 赋给 never,一旦以后新增一个 variant 却忘了处理,TypeScript 会在此处报错,等于给未来的自己留了一道护栏。

三、把事件回调的参数也收敛掉

自定义事件不要一律写成 (e: any) => void。给回调一个精确的参数类型,父组件传函数时就能拿到正确的字段。

type UploadProps = {
  onProgress: (payload: { loaded: number; total: number }) => void;
};

function Upload({ onProgress }: UploadProps) {
  onProgress({ loaded: 40, total: 100 });
}

小结

泛型解决“组件吃得下任意但类型自洽的数据”,可辨识联合解决“组件有多种互斥形态时要穷尽处理”。两者结合,组件的 props 接口会从“尽力而为”变成“编译期担保”。

T

test1

文章作者

为什么要在组件上做类型收敛 很多团队把组件的 props 写成宽松的 any 或大而全的可选字段,结果运行时才暴露“少传...

分类
技术
发布时间
2026-10-29
字数
约 1978 字
阅读
16 次