类型简述
一些React的内置类型
- React.ReactElement ---- 使用React.createElement创建 可以理解为React中的JSX元素
- React.ReactNode ----
xxxxxxx的合法类型
- React.CSSProperties —组件内联的style对象的类型
- React.RefObject ----React.createRef创建的类型,只读不可改
- React.MutableRefObject ----useRef创建的类型,可以修改
组件声明
组件声明分为类组件和函数组件
类组件
类组件使用定义主要为React.Component<P,S>和React.PureComponent<P,S,SS>
interface AppProps{
value:string
}
interface AppState{
count:number
}
class App extends React.Component<AppProps,AppStore>{
static defaultProps = {
value:''
};
state = {
count:0
}
}
React.Component<P,S> 这里P是props的类型,S是state的类型,可以写为React.Component,因为state的类型会自己推断
在上面PureComponent中还有个SS,这个ss是getSnapshotBeforeUpdate的返回值
函数组件
函数组件定义的方式简单来看两种,一种是使用React.FC,一种是直接给props写上定义
interface AppProps{
value?:string
}
const App:React.FC<AppProps> = ({value="",children})=>{
//...
}
React.FC的意思是FunctionComponent
如果使用了React.FC,它在定义里就已经规定好了children的类型和函数的返回值 所以可以直接使用children
如果是直接给props写上定义 就需要自己定义children的类型
interface AppProps{
value?:string;
children?:React.ReactNode; //自己定义children的类型
}
function App({value="",children}:AppProps){
return <>{children}</>
}
使用function来定义而不是箭头函数的优点是可以使用泛型组件
Hooks声明
hooks的声明如果不知道如何用ts定义可以直接点进来看
useState
useState可以使用泛型传参或自动推断
const [state,setState] = useState('')//state的类型为为string,自动推断
const [state,setState] = useState<string>()//state的类型为string|undefined
//给初值
const [state,setState] = useState<string|null>(null)//state的类型为string | null
useRef
useRef同样也会自动推断
const ref = useRef("") //ref.current的类型为string
//泛型
type Value = {value:string}
const ref = useRef<Value>({value:""});
//ref为html元素
const ref = useRef<HTMLDivElement>(null)
return <div ref={ref}/>
需要注意的是如果ref为元素 那么初始值得写个null才不会报错
useReducer
useReducer相对来说要写得更多一点 可以自动推断,
所以不需要手动写泛型类型
//state 类型
interface ReducerState {
value:String;
}
//action 类型
interface AnyAction {
type:String;
[key:string]:any
}
//reducer 函数
const reducer:React.Reducer<ReducerState,AnyAction> = (state,action)=>{
switch(action.type){
default:
return state;
}
}
//初始值
const initialState:ReducerState = {value:""}
const [state,dispatch] = useReducer(reducer,initialState)
//state的类型为ReducerState
//dispatch的类型为React.Dispatch<AnyAction
Action也可以是多个不同的Action的联合类型
useImperativeHandle
useImperativeHandle 这个钩子可以把内部方法通过ref暴露出去, 用ts也是要写多一点 类型都需要标注清楚
所以需要使用到React.forwardRef,
//props
interface AppProps{
value:string;
}
// useImperativeHandle获取到ref的类型
interface Handle{
get:()=>string
}
const App = React.forwardRef<Handle,AppProps>(({value},ref)=>{
//定义
useImperativeHandle(ref,()=>({
get:()=>`handle get value:${value}`
}));
return null
})
//使用
const handleRef = useRef<Handle>(null)
// handleRef.current?.get();
return <App value="hello" ref={handleRef}/>
自定义hook需要注意的
有如下钩子
const useCustomHook = ()=>{
const [state,setState] = useState('')
const set = (value:string)=>{
if(!value) return
setState(value)
}
return [state,set]
}
//使用
const [state,setState] = useCustomHook()
setState('hello') // This expression is not callable
自定义钩子还需要自定义返回值才行
const useCustomHook = ()=>{}
const useCustomHook = ():[String,(value:string)=>viod]=>{}
React.forwardRef
React.forwardRef<T,P={}>只需要传props的类型和ref的类型,第一个T是ref的类型 P是props的类型
const App = React.forwardRef<HTMLDivElement,AppProps>(({value},ref)=>{
return <div ref={ref}/>
})
//使用
const ref = useRef<HTMLDivElement>(null)
return <App value="hello" ref={ref}/>
React.ForwardRefRenderFunction
定义为该类型的函数可以放进React.forwardRef函数中作为参数
//定义
const forwardRender:React.ForwardRenderFunction<
HTMLDivElement,AppProps>=({value},ref)=>{
return <div ref={ref}/>
}
const App = React.forwardRef(forwardRender)
// 使用
const ref = useRef<HTMLDivElement>(null)
return <App value="hello" ref={ref}/>
React.createContext
泛型有自动推断的功能 所以useContext就不需要再写上类型了
interface ContextType {
getPrefixCls:(value:string)=>string
}
const context = React.createContext<ContextType>({
getPrefixCls:(value)=>`prefix-${value}`
})
const App = ()=>{
const {getPrefixCls} = useContext(context)
getPrefixCls("App") //prefix-App
return null
}
React.cloneElement
如果使用的React.FC定义的组件 他的children类型默认是React.ReactNode,需要显式转为React.ReactElement
const App:React.FC = ({children})=>{
return React.cloneElement(children as React.ReactElement,{value:'hello'})
}
//也可以覆写定义
const App:React.FC<{children:React.ReactElement}>=({children})=>{
return React.cloneElement(children,{value:'hello'})
}
React.ComponentType
通过React.ComponentType
定义的组件可以将变量名传入组件,在组件内调用,高阶组件通常会使用
interface AppProps{
value:string
}
const App:React.FC<AppProps>=(props)=>{
return null
}
//React.ComponentType定义组件
function HOC<T>(Component:React.ComponentType<T>){
return function(props:T){
return <Component {...props}/>
}
}
const WrappedComponent = HOC(App)
//调用
<WrappedComponent value="hello"/>
泛型参数的组件
泛型参数的组件是typescript2.9 版本新增的 第一次看见是在ant-design里
一个简单的例子就是Select组件
<Select <number>>
<Select.Option value={1}>
1
</Select.Option>
<Select.Option value={2}>
1
</Select.Option>
</Select>
类组件的定义
// 定义泛型参数的组件
class GenericComponent<P> extends React.Component<P>{
internalProp:P;
constructor(props:P){
super(props);
this.internalProp = props
}
render(){
return null
}
}
type Props = {a:Number;b:string}
<GenericComponent<Props> a={10} b="hi"/> //ok
<GenericComponent<Props> a={10} b={20}/> //Error
函数组件的定义
function GenericComponent<P>(props:P){
const internalProp = useRef(props)
return null
}
箭头函数的组件在特定条件也能用泛型
//这样会解析报错
const GenericComponent = <P>(props:P) => {
const internalProp = useRef(props)
return null
}
{/* 泛型必须使用extends 关键字才能解析 */}
const GenericComponent = <P extends any>(props:P) =>{
const internalProp = useRef(props)
return null
}
函数组件写起来可简洁太多了…
事件处理
也是多种多样
const App = ()=>{
//React.MouseEventHandler
const onClick: React.MouseEventHandler<HTMLInputElement> = (e)=>{
console.log(e.currentTarget.value);
}
//React.ChangeEventHandler
const onChange:React.ChangeEventHandler<HTMLInputElement>=(e)=>{
console.log(e.currentTarget.value);
}
//React.FocusEventHandler
const onFocus:React.FocusEventHandler<HTMLInputElement>=(e)=>{
console.log(e.currentTarget.value);
}
return <input onClick={onClick} onChange={onChange} onFocus={onFocus}/>
}
如果有事件不清楚该如何定义类型,可以点组件上的事件名去看看定义
需要注意的是只有e.currentTarget才会有对应的元素类型,e.target是没有的,它的类型是EventTarget
ts自带了一些工具泛型,比如Omit、Pick,在开发的时候还是有帮助