跳到主要内容

types

参考https://react-typescript-cheatsheet.netlify.app/

常用类型

React.ReactElementJSX.Element

type Key = string | number
interface ReactElement<T, P> { // 伪代码
type: T,
props: P,
Key: Key | null
}
namespace JSX {
interface Element extends React.ReactElement<any, any> {}
}
const App = (): JSX.Element => <div>test</div>;

React.ReactNode

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

type ReactText = string | number
type ReactChild = ReactElement | ReactText
const App = ({ children }: { children?: React.ReactNode}) => {}

React.ComponentProps

type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
T extends JSXElementConstructor<infer P>
? P
: T extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[T]
: {};
const App = (props: { name: string } & React.ComponentProps<'button'>) => {
const { name, ...rest } = props
return <button {...rest} />
}

type Test = React.ComponentProps<typeof App>
信息

需要注意的是JSX.IntrinsicElements会包括一个额外的ref字段,并且类型为LegacyRef

type LegacyRef<T> = string | Ref<T>;
interface ClassAttributes<T> extends Attributes {
ref?: LegacyRef<T> | undefined;
}

实际情况下我们更多会使用ComponentPropsWithoutRef获取组件或HTML元素的props,而对于通过forwardRef创建的组件我们可以使用ComponentPropsWithRef获取其props

React.CSSProperties

type props = {
style: React.CSSProperties;
}

Form and Event

type props = {
onClick(event: React.MouseEvent<HTMLButtonElement>): void;
onClick2: React.MouseEventHandler<HTMLButtonElement>;
};
信息

如果不关心事件的具体类型,我们可以指定其为React.SyntheticEvent

函数组件

type myProps = {
count: number
}
const App = ({ count }: myProps) => <div>{count}</div>

类组件

type myProps = {
count: number;
}

type myState = {
name: string;
}
class Parent extends React.Component<myProps, myState> {
state: myState = {
name: 'akara'
}
render() {
const { name } = this.state
return <div>{name}</div>
}
}

Ref

export default class App extends React.Component<appProps, appState> {
myRef = React.createRef<HTMLButtonElement>()
render() {
return (
<>
<FancyButton ref={this.myRef} style={{color: 'red'}}>
akara
</FancyButton>
<button onClick={() => console.log(this.myRef.current)}>点我</button>
</>
)
}
}

type myProps = {
style?: React.CSSProperties;
children: React.ReactNode;
}

const FancyButton = React.forwardRef<HTMLButtonElement, myProps>((props, ref) => {
const {
style,
children,
} = props
return <button style={style} ref={ref}>{children}</button>
})

常见问题

class组件和函数组件的返回值类型不同

因为历史遗留原因,class组件返回值类型为React.ReactNode;而函数组件的返回值类型为JSX.Element | null

class A extends React.Component {
render() {
return 'aka' // React.ReactNode
}
}

function B() {
return 'aka' // 报错
}

不推荐使用React.FC

今天的普遍共识是不要去使用React.FC

顺带一提,React.FC和普通的函数组件还是有些区别的,比如React.FC提供了隐式的children类型定义

const A = ({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) => {
return <div>{title}{children}</div>
}

const B: React.FC<{
title: string;
// 隐式的定义了children
}> = ({
title,
children,
}) => {
return <div>{title}{children}</div>
}