在我學習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
不太行