React 开发应该了解的 TypeScript 模式

随着 TypeScript 在 React 生态系统中的采用率不断提高,了解高级模式可以显著提高您的代码质量、可扩展性和开发人员体验。本文重点介绍了 React 开发的基本 TypeScript 模式,以及帮助你充分利用这些工具的实际示例。

Discriminated unions (管理复杂的状态(数据))

Discriminated unions 是处理具有多个变体或 "模式" 的状态的有效方法。通过将联合类型与 "discriminator" 属性组合在一起,您可以确保类型安全并避免由无效状态引起的错误。

示例 状态加载

ts 复制代码
type FetchState =  
| { status: 'idle' }  
| { status: 'loading' }  
| { status: 'success'; data: string[] }  
| { status: 'error'; error: string };


const fetchReducer = (state: FetchState, action: any): FetchState => {  
  switch (action.type) {  
  case 'FETCH_START':  
    return { status: 'loading' };  
  case 'FETCH_SUCCESS':  
    return { status: 'success', data: action.payload };  
  case 'FETCH_ERROR':  
    return { status: 'error', error: action.payload };  
  default:  
    return state;  
  }  
};

为什么有用 Discriminated unions 允许您的状态转换是显式的,从而避免无效的组合,例如同时具有 dataerror

泛型:定义具有复用性和适应性的组件

泛型使你的组件或 hook 可重用,同时保留强类型定义。这对于处理具有不同数据结构的列表、表单或 API 特别有用。

示例, 可复用的表格组件

ts 复制代码
type TableProps<T> = {  
  data: T[];  
  renderRow: (item: T) => React.ReactNode;  
};  
  
function Table<T>({ data, renderRow }: TableProps<T>) {  
  return (  
    <table>  
      <tbody>
       {data.map((item, index) => <tr key={index}>{renderRow(item)}</tr>)}
      </tbody>  
  </table>);  
}

// Usage  
type User = { id: number; name: string };  
const users: User[] = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];  
  
<Table  
  data={users}  
  renderRow={(user) => (<>  
    <td>{user.id}</td>  
    <td>{user.name}</td>  
  </>)}  
/>;

为什么有用

泛型使您的组件具有适应性,而不会失去类型推理的优势,从而使您免于重复的代码。

Mapped Types: props 和 state 之间的转换

映射类型允许您通过转换现有类型来创建新类型。这在定义派生 state 或 prop 接口时特别有用。

示例, 部分表单prpos

ts 复制代码
type FormValues = {  
  name: string;  
  email: string;  
  age: number;  
};

type FormErrors<T> = {  
  [K in keyof T]?: string;  
};

const errors: FormErrors<FormValues> = {  
  name: "Name is required",  
  email: "Email is invalid",  
};

为什么有用

映射类型非常适合管理具有不同属性的表单、API 或配置对象。

React props 和 state 的高级类型

带有 defaultProps 的类型属性

使用 defaultProps 时,您可以通过利用 TypeScript 的部分类型支持来确保类型安全

ini 复制代码
type ButtonProps = {  
  label: string;  
  onClick?: () => void;  
};  
  
const Button = ({ label, onClick = () => {} }: ButtonProps) => (  
  <button onClick={onClick}>{label}</button>  
);

只读 State

要在您的状态中强制执行不可变性,请使用 ReadonlyReadonlyArray

ts 复制代码
type State = Readonly<{  
  items: string[];  
}>;  
  
const [state, setState] = useState<State>({ items: ['Item 1'] });

为什么有用

强类型的 props 和 state 减少了运行时错误,并使其他开发人员清楚地了解了你的意图。

使用 TypeScript 和 React 的动态表单

动态表单通常涉及依赖于用户输入的复杂类型。TypeScript 可以帮助强制执行正确性,即使对于动态结构也是如此。

动态表单字段

ts 复制代码
type Field = {  
  id: string;  
  label: string;  
  value: string;  
};

type FormState = {  
  fields: Field[];  
};

const DynamicForm: React.FC = () => {  
const [formState, setFormState] = useState<FormState>({ fields: [] });  
  
const addField = () => {  
  setFormState((prev) => ({  
    fields: [...prev.fields, { id: Date.now().toString(), label: '', value: '' }],  
  }));  
};  
  
  return (  
    <div>  
      {formState.fields.map((field) => (  
        <input  
            key={field.id}  
            placeholder={field.label}  
            value={field.value}  
            onChange={(e) =>  
            setFormState((prev) => ({  
            fields: prev.fields.map((f) =>  
              f.id === field.id ? { ...f, value: e.target.value } : f  
            ),  
       }))}  
    />  
  ))}  
     <button onClick={addField}>Add Field</button>  
    </div>  
  );  
};

为什么有用

动态表单是许多应用程序中的常见功能。TypeScript 确保每个字段都正确键入和更新。

总结

TypeScript 不仅仅是一个静态类型工具------它还是一种编写更健壮、可维护和可扩展的 React 应用程序的方法。通过掌握 discriminated unions(可区分联合)、泛型和高级 prop 类型等模式,您可以在项目中释放 TypeScript 的全部潜力。无论您是构建动态表单、可重用组件还是管理复杂状态,这些模式都能确保流畅高效的开发体验。

[原文地址](TypeScript Patterns You Should Know for React Development | by Dzmitry Ihnatovich | Medium)

广州有前端坑位滴滴我。

相关推荐
bigyoung2 小时前
arco design form表单自定义校验空值时注意事项
javascript·react.js
小钰能吃三碗饭2 小时前
第十篇:【React SSR 与 SSG】服务端渲染与静态生成实战指南
前端·react.js·next.js
洛小豆2 小时前
深入理解 JavaScript 的解构赋值
前端·javascript·typescript
三棵杨树2 小时前
TypeScript从零开始(六):类
前端·typescript
键指江湖3 小时前
React 对state进行保留和重置
javascript·react.js·ecmascript
Moon里4 小时前
【React】项目的搭建
react.js
懒羊羊我小弟5 小时前
Vue与React组件化设计对比
前端·vue.js·react.js
小满zs9 小时前
React-router v7 第五章(路由懒加载)
前端·react.js
尘寰ya16 小时前
前端面试-React篇
前端·react.js·面试