「優雅」的含義: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; // ... } // ...