揭秘性能优化背后的类型魔法:OverrideProps 如何拯救你的代码?

时间:2025-02-10 00:14 分类:其他教程

在项目的重构过程中,我意外地发现了一个性能隐患。每次使用 Input 组件时,我们都会采用内联箭头函数的方式处理输入值:

<Input onInput={(e) => {
  const value = e.currentTarget.value; // 处理值的逻辑
}}/>

然而,这种写法会导致每次渲染都创建一个新的回调函数,从而可能引发不必要的重渲染。为了解决这个问题,我决定将回调函数提取出来,并用 useCallback 包裹。但就在此时,我遇到了一个棘手的类型问题:

const handleInput = useCallback((e: ???) => {
  const value = e.currentTarget.value; // 处理值的逻辑
}, []);

在这个时候,我完全不知道 e 的具体类型。为了获取到正确的事件类型,我查阅了 React 的文档,并使用了 ComponentProps

import { ComponentProps } from 'react';
type InputProps = ComponentProps<'input'>;
const handleInput = useCallback((e: InputProps['onInput']) => {
  const value = e.currentTarget.value; // 处理值的逻辑
}, []);

然而,这种写法仍然让我感到困扰。我开始思考,如果能够封装一个新组件,直接传值给回调函数,那会怎么样呢?最初的想法是这样的:

interface CustomInputProps extends InputProps {
  onInput: (value: string) => void;
}

const CustomInput: React.FC<CustomInputProps> = ({
  onInput,
  ...props
}) => {
  const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
    onInput(e.currentTarget.value);
  };
  return (
    <Input {...props} onInput={handleInput} />
  );
};

但结果却遇到了类型错误,让我感到无比沮丧。正当我准备放弃的时候,我发现了 OverrideProps 这个工具类型。使用它重写后,代码变得非常优雅:

type OverrideProps<T, U> = Omit<T, keyof U> & U;

interface CustomInputProps extends OverrideProps<InputProps, { onInput: (value: string) => void }> {}

const CustomInput: React.FC<CustomInputProps> = ({
  onInput,
  ...props
}) => {
  const handleInput = (e: React.FormEvent<HTMLInputElement>) => {
    onInput(e.currentTarget.value);
  };
  return (
    <Input {...props} onInput={handleInput} />
  );
};

通过使用 OverrideProps,我不仅解决了类型覆盖的问题,还发现它还有更多强大的用法。例如,修改多个属性:

type EnhancedInputProps = OverrideProps<InputProps, { onInput: (value: string) => void; onChange: (value: string) => void; value: string; }}>

配合泛型使用,可以派生出各种类型的输入框:

type ValueInput<T> = OverrideProps<InputProps, { value: T; onChange: (value: T) => void; }>;

type NumberInput = ValueInput<number>;
type DateInput = ValueInput<Date>;

扩展原有属性也很简单:

type PhoneInputProps = OverrideProps<InputProps, { onInput: (value: string) => void; format?: 'CN' | 'US'; }>;

interface CustomPhoneInputProps extends PhoneInputProps {
  format: 'CN';
}

const CustomPhoneInput: React.FC<CustomPhoneInputProps> = ({
  format,
  ...props
}) => {
  // ...
};

实用技巧方面,保持类型收敛非常重要:

type GoodProps = OverrideProps<BaseProps, { onChange: (value: string) => void; }>;

// 避免的写法
type BadProps = OverrideProps<BaseProps, { onChange: any; }}>;

// 添加类型说明
interface CustomProps extends OverrideProps<BaseProps, { /** 值变化时的回调 */ onChange: (value: string) => void; }> {}

小结

OverrideProps 解决了在组件二次封装时常见的类型覆盖问题。它既保留了原组件的类型定义,又能精确地修改我们需要改变的属性类型。使用 OverrideProps 的几个好处包括:

  1. 代码更简洁:不用手动写一堆 Omit 类型提示。
  2. 更准确:维护更方便,想改什么属性直接加就行。
  3. 避免无脑 AnyScript:没有无脑 AnyScript 的感觉真好!

通过这个案例,我深刻体会到在编程中,一个小小的优化可能带来意想不到的收获。希望这篇文章能为你带来启发,让你在编写代码时更加得心应手。

声明:

1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。

2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。

3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。

4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。

本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 0人参与,0条评论
查看更多

Copyright 2005-2024 yuanmayuan.com 源码园 版权所有 备案信息

声明: 本站非腾讯QQ官方网站 所有软件和文章来自互联网 如有异议 请与本站联系 本站为非赢利性网站 不接受任何赞助和广告