在我学习typescript
时,想在react
中使用typescript
写代码,从头开始的时候是懵逼的,由于官方文档并无使用typescript
的教程,可能是本身在网上查,本身看定义摸索html
因此今天把我用过的,总结概括一下,但愿能帮助到一样在摸索的同窗react
如下代码react
版本为16.13.1
,在create-react-app
官方typescript
模版中无报错typescript
一些React
的内置类型express
React.ReactElement
—— 使用React.createElement
建立的,能够简单理解为React
中的JSX
的元素React.ReactNode
—— <div>xxx</div>
xxx的合法类型React.CSSProperties
—— 组件内联的style
对象的类型React.RefObject
—— React.createRef
建立的类型,只读不可改React.MutableRefObject
—— useRef
建立的类型,能够修改组件声明分为类组件和函数组件数组
类组件使用的定义主要为React.Component<P,S>
和React.PureComponent<P,S,SS>
app
interface AppProps {
value: string;
}
interface AppState {
count: number;
}
class App extends React.Component<AppProps, AppState> {
static defaultProps = {
value: "",
};
state = {
count: 0,
};
}
复制代码
React.Component<P,S>
这里的P
是props
的类型,S
是state
的类型,能够写为React.Component<AppProp>
,由于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
ui
若是是直接给props
写上定义,就须要本身定义children
的类型
interface AppProps {
value?: string;
children?: React.ReactNode; // 本身定义children的类型
}
function App({ value = "", children }: AppProps) {
return <>{children}</>;
}
复制代码
使用function
来定义而不是箭头函数的优势是可使用泛型组件
hooks
的声明若是不知道如何用ts
定义能够直接点进去看看
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
一样也会自动推断
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
相对来讲要写的更多一点,能够自动推断,因此不须要手动写泛型类型(其实我也不知道手动写怎么写Orz)
// 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
这个钩子能够把内部方法经过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} />;
复制代码
有以下钩子
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 callabl
复制代码
自定钩子还须要定义返回值才行
- const useCustomHook = () => {
+ const useCustomHook = (): [string, (value: string) => void] => {
复制代码
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.forwardRef
函数中做为参数
// 定义
const forwardRender: React.ForwardRefRenderFunction<
HTMLDivElement,
AppProps
> = ({ value }, ref) => {
return <div ref={ref} />;
};
const App = React.forwardRef(forwardRender);
// 使用
const ref = useRef<HTMLDivElement>(null);
return <App value="hello" ref={ref} />;
复制代码
泛型有自动推断的功能,因此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.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<P>
定义的组件能够将变量名传入组件,在组件内调用,高阶组件一般会使用
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" />
复制代码
泛型参数的组件是typescript
2.9版本新增的,第一次看见是在ant-deisgn
里
一个很简单的例子就是Select
组件
<Select<number>>
<Select.Option value={1}>1</Select.Option>
<Select.Option value={2}>2</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,
在开发的时候仍是有帮助,能够看看我之前的总结
最后,祝你们身体健康,工做顺利!
太惨了,tsx连代码高亮都没有,只能说仍是prismjs
好使,highlightjs
不太行