「优雅」的含义:html
import * as React from 'react'; // 若是在tsconfig中设置了"allowSyntheticDefaultImports": true // 你还能够更精练地import react: // import React from "react"; interface IProps { // CSSProperties提供样式声明的类型信息 // 用户传入style的时候就可以得到类型检查和代码补全 style?: React.CSSProperties; // 使用@types/react提供的事件类型定义,这里指定event.target的类型是HTMLButtonElement onClick(event: React.MouseEvent<HTMLButtonElement>): void; // ... } const MyComponent: React.FC<IProps> = (props) => { const { children, ...restProps } = props; return <div {...restProps}>{children}</div>; }
IProps
无需声明children
属性的类型。React.FC
会自动为props添加这个属性类型。react
固然,若是children指望一个render prop,或者指望其余特殊的值,那么你仍是要本身给children
声明类型,而不是使用默认的React.ReactNode
。
props
无需作类型标注。若是你须要定义defaultProps,那么不要使用React.FC,由于React.FC对defaultProps的支持不是很好:git
const defaultProps = { who: "Johny Five" }; type IProps = { age: number } & typeof defaultProps; export const Greet = (props: IProps) => { return <div>123</div> }; Greet.defaultProps = defaultProps;
事实上,一个提议在函数组件中废弃defaultProps的React rfc已经被接受,因此之后仍是尽可能减小在函数组件上使用defaultProps,使用ES6原生的参数解构+默认参数特性就已经可以知足须要:github
const TestFunction: FunctionComponent<Props> = ({ foo = "bar" }) => <div>{foo}</div>
interface IProps { message: string; } interface IState { count: number; } export class MyComponent extends React.Component<IProps, IState> { state: IState = { // duplicate IState annotation for better type inference count: 0 }; render() { return ( <div> {this.props.message} {this.state.count} </div> ); } }
若是你经过声明state属性来初始化state,那么你须要为这个属性增长IState类型标注。虽然这与前面的React.Component<IProps, IState>
有重复的嫌疑,可是这二者其实是不一样的:typescript
React.Component<IProps, IState>
只是标注了基类的state属性类型。this.state
会以子类中的state属性声明做为类型信息的来源。可渲染节点就是:能够直接被组件渲染函数返回的值。redux
与可渲染节点有关的类型定义以下(摘录自@types/react):数组
type ReactText = string | number; type ReactChild = ReactElement | ReactText; interface ReactNodeArray extends Array<ReactNode> {} type ReactFragment = {} | ReactNodeArray; type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
React.FC<Props>
(即 React.FunctionComponent<Props>
)React.Component<Props, State>
React.ComponentType<Props>
(即ComponentClass<P> | FunctionComponent<P>
)
在写HOC的时候常常用到。安全
const withState = <P extends WrappedComponentProps>( WrappedComponent: React.ComponentType<P>, ) => { ...
好比,如下例子获取并扩展了<button>
的props类型:app
export const PrimaryButton = ( props: Props & React.HTMLProps<HTMLButtonElement> ) => <Button size={ButtonSizes.default} {...props} />;
PrimaryButton可以接受全部原生<button>
所接受的props。关键在于React.HTMLProps
。ide
import { Button } from "library"; // but doesn't export ButtonProps! oh no! type ButtonProps = React.ComponentProps<typeof Button>; // no problem! grab your own! type AlertButtonProps = Omit<ButtonProps, "onClick">; // modify const AlertButton: React.FC<AlertButtonProps> = props => ( <Button onClick={() => alert("hello")} {...props} /> );
@types/react提供了各类事件的类型,好比如下是使用React.FormEvent
的例子:
class App extends React.Component< {}, { text: string } > { state = { text: '', } onChange = (e: React.FormEvent<HTMLInputElement>): void => { this.setState({ text: e.currentTarget.value }) } render() { return ( <div> <input type="text" value={this.state.text} onChange={this.onChange} /> </div> ) } }
在React中,全部事件(包括FormEvent、KeyboardEvent、MouseEvent等)都是SyntheticEvent的子类型。他们在@types/react中定义以下:
// DOM事件的基本属性都定义在这里 interface BaseSyntheticEvent<E = object, C = any, T = any> { nativeEvent: E; currentTarget: C; target: T; bubbles: boolean; cancelable: boolean; defaultPrevented: boolean; eventPhase: number; isTrusted: boolean; preventDefault(): void; isDefaultPrevented(): boolean; stopPropagation(): void; isPropagationStopped(): boolean; persist(): void; timeStamp: number; type: string; } interface SyntheticEvent<T = Element, E = Event> extends BaseSyntheticEvent<E, EventTarget & T, EventTarget> {} // 具体的事件类型: interface FormEvent<T = Element> extends SyntheticEvent<T> {} interface KeyboardEvent<T = Element> extends SyntheticEvent<T, NativeKeyboardEvent> { altKey: boolean; // ... } interface MouseEvent<T = Element, E = NativeMouseEvent> extends SyntheticEvent<T, E> { altKey: boolean; // ... } // ...