谈谈在专栏【React+TS前台项目实战】项目中用到的Typescript定义方式


前言

今天不讲实战,来讲一下我们专栏【 React+TS前台项目实战 】中用到的Typescript用法,比起网上那些直接概念式地讲,通过实战我们更能加深对Typescript方面相关知识的理解。


1. interface和type差别

这两种定义类型声明的主要区别在于interface定义的是对象,而type可以定义不限于对象的基本数据类型,联合类型,交叉类型等。

2. omit剔除

在项目封装input组件时,会使用到Omit去剔除声明中某个属性,再联合自己额外定义的属性,如下展示的是部分代码

type Props = Omit<ComponentPropsWithoutRef<"input">, "size"> & {
  // 按下回车的回调
  onEnter?: () => void;
  // 清除输入框的回调
  onClear?: () => void;
  // 是否显示加载状态
  loading?: boolean;
  // 输入框大小
  size?: "default" | "small" | "large" | undefined;
  // 输入框前缀
  hasPrefix?: boolean;
};

3. 联合类型和交叉类型使用

这里把联合和或一起举例,在Link链接组件中运用到了交叉类型的使用,组合自己定义的声明;在Search组件封装时,运用到了联合类型的使用,由于搜索结果类型不同,展示的数据结构不一样,这时候就可以用或把不同类型声明区分开来

// 交叉类型的使用
type LinkProps = Omit<RouterLinkProps, "ref"> & {
  ref?: ForwardedRef<HTMLAnchorElement>;
  to?: string;
  className?: string;
  children?: ReactNode;
};
import { Response } from '@/request/types'
import { Block } from '@/models/Block'
import { Transaction } from '@/models/Transaction'
export enum SearchResultType {
  Block = 'block',
  Transaction = 'ckb_transaction',
}
// 联合类型的使用
export type SearchResult =
  | Response.Wrapper<Block, SearchResultType.Block>
  | Response.Wrapper<Transaction, SearchResultType.Transaction>

4. 使用命名空间暴露类型声明

在请求封装中,使用到一系列类型声明,我们将他包装在了Response命名空间里面

export namespace Response {
  export interface Response<T> {
    data: T
    meta?: Meta
    error?: Error[]
  }

  export interface Error {
    id: string
    code: number
    status: number
    title: string
    detail: string
    href: string
  }

  export interface Meta {
    total: number
    pageSize: number
  }

  export interface Wrapper<A, T = string> {
    id: number
    type: T
    attributes: A
  }
}

5. 使用ForwardedRef传递ref

这里同样举例Link组件封装,做到了传递ref的功能

type LinkProps = Omit<RouterLinkProps, "ref"> & {
  ref?: ForwardedRef<HTMLAnchorElement>;
  to?: string;
  className?: string;
  children?: ReactNode;
};
const Link = forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => {
  // ...
});

6. 函数返回

在弹窗组件Dialog的封装中,我们定义声明类型为返回void。

void  onClose: () => void;

7.Record

简单讲,其实Record就是定义一个对象的一些key键名,然后定义键值的类型,在Searh组件的封装中,我们使用了它来定义搜索结果的数据类型声明。

export enum SearchResultType {
  Block = 'block',
  Transaction = 'ckb_transaction'
}
export type SearchResult =
  | Response.Wrapper<Block, SearchResultType.Block>
  | Response.Wrapper<Transaction, SearchResultType.Transaction>
Record<SearchResultType, SearchResult[]>

8.泛型使用

泛型是一个通用的数据类型参数,可代替任何类型,达到复用的效果。这里同样举了请求类型声明的定义上。

// 定义
export namespace Response {
 export interface Wrapper<A, T = string> {
    id: number
    type: T
    attributes: A
  }
 }
// 使用
type SearchResult =
  | Response.Wrapper<Block, SearchResultType.Block>

9. 继承

这里定义了一个Props的类型声明,同时引用了ComponentProps类型声明,继承了其中div属性的类型声明

import { ComponentProps, ReactNode } from 'react'
interface Props<T> extends ComponentProps<'div'> {
  data: T[]
}

10. 定义函数返回类型为promise

函数返回类型为promise,这个在Button组件的封装中使用了。

  beforeChange?: (() => Promise<void>) | undefined;

11. 返回reactNode

这个类型通常用于函数组件的返回值,以便能够接受不同类型的内容,包括React元素、文本、数组或者null。这个在Modal组件的封装中使用了。

 type Props = {
  // 模态框内容
  children: React.ReactNode;
};

总结

上面就是专栏【 React+TS前台项目实战 】目前为止主要用到的类型声明定义的方式,接下来会继续这个专栏文章的发布,还会继续用到其他方式进行类型声明定义,请持续关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值