背景 最近用 TS 重写了部分工具函数,其中用到了泛型,在这里做一个分享,帮助大家快速熟悉泛型。
泛型 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
简单例子 首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值:
1 2 3 function createArray (length: number , value: any ): Array <any > { return Array (length).fill(value) }
这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型。
使用泛型后,类型就可以传递了
1 2 3 function createArray <T >(length: number , value: T ): Array <T > { return Array (length).fill(value) }
接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来。
实现一个 withStyles HOC withStyles 的作用是将 CSS Modules 的 styles 对象注入原组件,以达到「样式参数化」的目的。并且可以通过不断叠加 hoc 实现样式的复用。这里先不讨论该 HOC 的使用场景,它就是一个平平无奇的 HOC,我们用它做例子看看泛型怎么使用。
1 const ComponentWithStyles = withStyles(styles)(Component)
使用泛型改造 withStyles.tsx
由于对传入的组件属性不可知,以下代码用 any 随便糊弄一顿后,我们会发现它跟我们用 JS 写没有什么区别,TS 的作用没有发挥出来。
1 2 3 4 5 6 7 8 const withStyles = (stylesProp: object ) => (WrappedComponent: any ) => { const ComponentWithStyles = ({ styles, ...props }: React.FC<any > ) => { const comStyles = Object .assign({}, stylesProp, styles) return <WrappedComponent styles={comStyles} {...props} /> } return ComponentWithStyles }
接着,我们使用泛型改造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 interface WithStylesProps { styles?: object } const withStyles = <P extends WithStylesProps>(stylesProp: object ) => ( WrappedComponent: React.FC<P> ) => { const WrapCom = React.forwardRef<React.FC<P>, P>(function WrapCom ( props, ref ) { const { styles, ...otherProps } = props const comStyles = Object .assign({}, stylesProp, styles) return ( <WrappedComponent styles={comStyles} {...(otherProps as P)} ref={ref} /> ) }) return WrapCom }
用法 1 const ComponentWithStyles = withStyles<ComponentProps>(styles)(Component)
使用的时候可以传入源组件的 Props 类型定义: ComponentPropsm,这样,使用 HOC 的时候就保留了源组件的类型提示了。
window.fetch 的简单封装 背景 项目中存在大量的数据请求逻辑,所以需要对 fetch 进行简单封装
用法 1 2 3 fetch('//baidu.com' ).then((res ) => { console .log(res) })
我们知道,Response 类的 json()方法返回默认的类型推断为 any,所以我们无法知道接口返回的 json 数据类型。
使用泛型:对 window.fetch 进行简单封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import fetch from 'isomorphic-fetch' import fetchJsonp from 'fetch-jsonp' import { stringify } from 'qs' export interface FrResponse<T = any> { data?: T err?: any } export interface FrPromise<T = any> extends Promise<FrResponse<T>> {}export default function request <T = any >( url: string , { jsonp, query, ...options }: { jsonp?: boolean query?: object } = {} ): FrPromise <T > { const fetchFunction = jsonp ? fetchJsonp : process.env.NODE_ENV !== 'production' ? window .fetch : fetch return fetchFunction(url + formatQuery(query), { credentials: 'include' , ...options, }) .then((res ) => res && checkStatus(res, jsonp)) .then((response ) => response.json()) .then((data: T ) => ({ data })) .catch((err ) => ({ err })) }
使用 ts 之后,我们可以简单通过泛型约束后台返回的 JSON 数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 interface TypeActivityStatus { status: number msg: string list: null | [] current: number begin: number end: number stage: number stageBegin: number stageEnd: number } fetch<TypeActivityStatus>( '//baidu.com' ).then((res ) => { resolve(res.data && res.data.status) })
参考 深入理解 TypeScript
React Higher-Order Components in TypeScript