起首声明, 这篇文章是想申明一下最新版本的 TypeScript(3.0) 的新特征带来的极大的 React 开辟体验提拔. 而不是怎样运用 TypeScript 开辟 React 运用.
这个特征就是对defaultProps
的支撑, 在 TypeScript 的 Wiki 中有申明, 详细能够参考这里: Support for defaultProps
in JSX.
在3.0版本之前, 我们在开辟 React 运用, 尤其是在合营 redux 一类 HOC 库的时刻, 常常用到诸如 connect(TodoList)
, withRouter(TodoList)
之类的封装. 而这些函数实在都能够用装潢器
的体式格局来挪用, 比方:
export interface TodoListProps extends RouteComponentProps<{}> {
todos: Todo[];
}
@withRouter
@connect(mapStateToProps)
export class TodoList extends PureComponent<TodoListProps, {}> {
render() {
return null
}
}
但是在连系 TypeScript 的时刻, 这中心有个题目, 就是装潢器会自动注入一些 props 给组件, 这一部份属性不须要外部传入, 因而是可选的, 在strictNullCheck
属性开启的时刻, 就会涌现属性争执. 由于 TS 给不允许装潢器修正被装潢的对象的范例, 因而在 props 定义中为required
属性依旧为required
.
比方关于上面的例子, 在实例化TodoList
这个组件的时刻, 必须要传入一切的TodoListProps
所定义的属性, 不然会有TS2322
毛病.
而在 TS 3.0 中, 能够声明defaultProps
属性来表明某些属性对外部组件而言是可选的. 比方:
@withRouter
@connect((state) => ({ todos: state.todos })
export class TodoList extends PureComponent<TodoListProps, {}> {
static defaultProps: TodoListProps
render() {
return null
}
}
这里的static defaultProps: TodoListProps
表明, 一切的TodoList
的 props TodoListProps
对外部组件都是可选的. 这就意味着外部组件能够什么属性都不必传也不会有毛病. 同时内部而言一切的属性都是NotNullable
.
综上, 通常情况下, 我们的一个组件会有一部份属性由装潢器注入, 而另一部份则须要外部实例化时传入, 因而, 能够将一个组件的 props 接口声明成两层构造, 第一层为由装潢器注入的部份, 第二层则为完全的属性接口, 然后将defaultProps
设置成为第一层接口即可. 比方:
export interface TodoListInnerProps extends RouteComponentProps<{}> {
todos: Todo[];
}
export interface TodoListProps extends TodoListInnerProps {
className?: string;
onLoad?(): void;
}
@withRouter
@connect((state) => ({ todos: state.todos })
export class TodoList extends PureComponent<TodoListProps, {}> {
static defaultProps: TodoListInnerProps
render() {
return null
}
}
须要注重的是:
- TypeScript 要
3.0.1
以上 -
@types/react
要最新版 withRouter
,connect
等函数在@types
中, 署名有题目, 须要手动修正一下:import { ComponentClass } from 'react' import { connect as nativeConnect, MapDispatchToPropsParam, MapStateToPropsParam } from 'react-redux' import { withRouter as nativeWithRouter } from 'react-router' export type ComponentDecorator<P = any> = <T extends ComponentClass<P>>(WrappedComponent: T) => T export const connect: <P, S = Todo>( mapState: MapStateToPropsParam<Partial<P>, P, S>, mapDispatch?: MapDispatchToPropsParam<Partial<P>, P> ) => ComponentDecorator = nativeConnect as any export const withRouter: ComponentDecorator = nativeWithRouter as any