React+ts写组件小技巧-原生属性的继承和重写

2,886 阅读1分钟

在写组件时经常会遇到这么一种情况,比如写一个MyInput组件

<MyInput type="text" name="input" id="input" onInput={()=>alert('input')}/>

像例子中的type,name,id,onInput都是html的原生属性,在React+ts中需要通过interface定义才能传递,但是一个一个定义太麻烦了,有没有简单的方法呢。

原生属性的继承

其实在React中已经定义好了原生html属性的接口了,通过React.InputHTMLAttributes就可以把原生属性都继承过来,具体如下

import React from 'React';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}

export const MyInput: React.FC<InputProps> = (props) => {
  return (
    <input
      {...props}
    />
  )
};

这里只举例input,其他的比如button就继承React.ButtonHTMLAttributes<HTMLButtonElement>具体可以在 node_modules\@types\react\index.d.ts 里看到

原生属性的重写

原生属性的重写需要用到typescript内置的泛型工具Omit,它的作用是可以排除某几个属性。比如我想重新定义type的属性,就可以这样写

import React from 'React';
const tuple = <T extends string[]>(...args: T) => args;
const InputTypes = tuple('typeA','typeB','typeC');
export type InputType = typeof InputTypes[number];
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>,'type'> { // 代表继承除type外是所有的input属性
  type: InputType
}

然后可以使用rc-uitl工具把传过来的props中的type删掉,赋给原生input,完整代码

import React from 'React';
import omit from 'rc-util/lib/omit';
const tuple = <T extends string[]>(...args: T) => args;
const InputTypes = tuple('typeA','typeB','typeC');
export type InputType = typeof InputTypes[number];
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>,'type'> {
  type: InputType
}

export const MyInput: React.FC<InputProps> = (props) => {
  const { type } = props
  // todo 处理type
  const other = omit(props,['type']) //删除props中的type
  return (
    <input
      {...other}
    />
  )
};