React+TypeScript教程之7 - 泛型


由微软推出的TypeScript自从一推出就广受关注,现在无论开发前端React/Vue,还是后端API,很多项目中都广泛接受了TypeScript。下面介绍如何在React中通过TypeScript来使用泛型。

TypeScript

基本组件

先来看一个最基本的List组件:

ListComponent.tsx

type ListProps = {
  data: string[];
  clickHandler: (value: string) => void;
};

export const ListComponent = ({ data, clickHandler }: ListProps) => {
  return (
    <div>
      <h2>Generic list component</h2>
      {data.map((item, index) => {
        return (
          <li key={index} onClick={() => clickHandler(item)}>
            {item}
          </li>
        );
      })}
    </div>
  );
};

调用部分

function App() {
  const students = ['Lucy', 'Paula', 'Jim', 'Andy'];
  const handleClick = (item: string) => {
    console.log(item);
  }

  return (
    <div className="App">
      <ListComponent data={students} clickHandler={handleClick}/>
    </div>
  );
}

使用泛型

在上面例子中,ListComponent只能处理字符型的数据。如果传递过来的是数字,或者对象类型,TS就会报错。这个时候,可以通过联合类型来解决这个问题:

type ListProps = {
  data: string[] | number[];
  clickHandler: (value: string | number) => void;
};

但这种方式的通用性仍然很差,尤其是在处理对象数组的时候。那么,就可以使用泛型来达到这个要求:

type ListProps<T> = {
  data: T[];
  clickHandler: (value: T) => void;
};

export const ListComponent = <T extends {name: string}>({
  data,
  clickHandler,
}: ListProps<T>) => {
  return (
    <div>
      <h2>Generic list component</h2>
      {data.map((item, index) => {
        return (
          <li key={index} onClick={() => clickHandler(item)}>
            {item.name}
          </li>
        );
      })}
    </div>
  );
};

需要注意的是,这里对T的类型进行了限定,它继承自任何包含’name’属性的对象。因此,在使用这个组件的时候,就要确保传入的数组中每个对象都包含’name’属性:

function App() {
  const students = [
    { name: "Lucy", age: 20 },
    { name: "Paula", age: 21 },
    { name: "Jim", age: 18 },
    { name: "Andy", age: 22 },
  ];
  const handleClick = (item: {name: string}) => {
    console.log(item);
  };

  return (
    <div className="App">
      <ListComponent data={students} clickHandler={handleClick} />
    </div>
  );
}

注意事项

可以使用以下方式来限定这个组件能够使用的类型,比如:

export const MyComponent = <T extends string | number>(
  data,
  processing,
) = {
  // ...
}

如果想要允许任何对象类型的话,可以这样:

export const MyComponent = <T extends {}>(

或者只允许某种特定的对象类型(对象中至少包含指定的属性,比如name,age,address,也可以包含更多的属性):

export const MyComponent = <T extends {name:string, age:number}>(

文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !
  目录