preface

When I tried to learn typescript and write code in typescript in react, I was completely confused because there were no official typescript tutorials. I had to look up the definitions on the Internet

So today I have used, summed up, hope to help the same in groping students

The following code is in the React version 16.13.1 and has no error in the create-react-app official typescript template

Type a brief introduction

Some built-in types of React

  • React.ReactElement– the use ofReact.createElementCreate, can be simply understood asReactIn theJSXThe elements of the
  • React.ReactNode<div>xxx</div>The legal type of XXX
  • React.CSSProperties— Component inlinestyleType of object
  • React.RefObjectReact.createRefThe created type is read-only and cannot be changed
  • React.MutableRefObjectuseRefThe created type can be modified
  • .

Component declarations

Component declarations are classified into class components and function components

Class components

React.purecomponent

and React.pureComponent

,s,ss>
,s>

interface AppProps {
  value: string;
}
interface AppState {
  count: number;
}
class App extends React.Component<AppProps, AppState> {
  static defaultProps = {
    value: "",
  };
  state = {
    count: 0,
  };
}
Copy the code

React.prop

Where P is the props type and S is the state type, we can write react.prop

because the state type will infer itself

,s>

There is also an SS in the above PureComponent, which is the return value of getSnapshotBeforeUpdate

Function component

There are two simple ways to define a function component. One is to use react. FC, or to write the definition directly to the props

interface AppProps { value? : string; } const App: React.FC<AppProps> = ({ value = '', children }) => { // ... };Copy the code

If you use the function react.fc, you can use the children function. If you use the function react.fc, you can use the children function

If you write the definition for props, you need to define the type for children

interface AppProps { value? : string; children? : React.ReactNode; } function function ({value = "", children} : AppProps) {return <>{children}</>; }Copy the code

The advantage of using function instead of arrow functions is that you can use generic components

Hooks statement

* * * * * * * * * * * * * * * * * * *

useState

UseState can use generic passarguments or automatic inference

const [state, setState] = useState(' '); // The type of state is string
const [state, setState] = useState<string> ();/ / state of type string | is undefined
/ / to initial value
const [state, setState] = useState<string | null> (null); / / state of type string | null
Copy the code

useRef

UseRef also inferences automatically

const ref = useRef(""); // Current is of type string
/ / generics
type Value = { value: string };
const ref = useRef<Value>({ value: "" });
// ref is an HTML element
const ref = useRef<HTMLDivElement>(null);
return <div ref={ref} />;
Copy the code

Note that if ref is an element, then the initial value is null without an error

useReducer

UseReducer has a little bit more to do, and it can be inferred automatically, so you don’t need to write generic types manually (actually I don’t know how to write Orz manually either)

/ / state type
interface ReducerState {
  value: string;
}
/ / the action type
interface AnyAction {
  type: string;
  [key: string] :any;
}
/ / reducer function
const reducer: React.Reducer<ReducerState, AnyAction> = (state, action) = > {
  switch (action.type) {
    default:
      returnstate; }};/ / initial value
const initialState: ReducerState = { value: "" };

const [state, dispatch] = useReducer(reducer, initialState);
// The type of state is ReducerState
// The type of dispatch is React.dispatch 
      
Copy the code

An Action can also be a union of several different actions

useImperativeHandle

The useImperativeHandle hook exposes internal methods via ref. Ts is a bit more explicit and the type should be clearly marked

So you need to use React. ForwardRef, which you can see in the next section

// props interface AppProps { value: string; } // useImperativeHandle gets the type of ref; interface Handle {get: () => string; } const App = react.callback <Handle, AppProps>(({value}, ref) => useImperativeHandle(ref, () => ({get: () => `handle get value : ${value}`, })); return null; }); // Use const handleRef = useRef<Handle>(null); // handleRef.current? .get(); return <App value="hello" ref={handleRef} />;Copy the code

Custom hooks need attention

There are the following hooks

const useCustomHook = (a)= > {
  const [state, setState] = useState("");
  const set = (value: string) = > {
    if(! value)return;
    setState(value);
  };
  return [state, set];
};
/ / use
const [state, setState] = useCustomHook();
setState('hello') // This expression is not callabl
Copy the code

Custom hooks also need to define a return value

- const useCustomHook = () => {
+ const useCustomHook = (): [string, (value: string) => void] => {
Copy the code

React.forwardRef

> > (props/ref (props/ref (props/ref)

const App = React.forwardRef<HTMLDivElement, AppProps>(({ value }, ref) => { return <div ref={ref} />; }); // Const ref = useRef<HTMLDivElement>(null); return <App value="hello" ref={ref} />;Copy the code

React.ForwardRefRenderFunction

A function defined with this type can be put into the React. ForwardRef function as an argument

// Define 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} />;Copy the code

React.createContext

Generics have automatic inference, so useContext does not need to write the type

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;
};
Copy the code

React.cloneElement

If you use a component defined in React.FC, the children type defaults to React.ReactNode and needs to be explicitly converted to 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" }); };Copy the code

React.ComponentType

A component defined by react.ponentType

can pass the variable name into the component and be called within the component, which higher-order components typically use

interface AppProps { value: string; } const App: React.FC<AppProps> = (props) => { return null; }; Function HOC<T>(Component: react.ponentType <T>) {return function (props: props) T) { return <Component {... props} />; }; } const WrappedComponent = HOC(App); // Call <WrappedComponent value="hello" />Copy the code

Component of a generic parameter

Components for generic parameters are new to typescript2.9 and were first seen in Ant-Deisgn

A simple example is the Select component

<Select<number>>
  <Select.Option value={1}>1</Select.Option>
  <Select.Option value={2}>2</Select.Option>
</Select>
Copy the code

Class component definition

Class GenericComponent<P> extends React.Com <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} />; // ErrorCopy the code

Definition of a function component

function GenericComponent<P>(props: P) {
  const internalProp = useRef(props)
  return null;
}
Copy the code

Components of arrow functions can also be generics under certain conditions

Const GenericComponent = <P>(props: P) =>{const internalProp = useRef(props); return null; <P extends any>(props: P) =>{const internalProp = useRef(props); return null; }Copy the code

Function components are much cleaner to write…

The event processing

It’s diverse

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} />;
};
Copy the code

If you don’t know how to define an event type, you can click on the event name on the component to see the definition

Note that only e.currenttarget has an element type; e.target does not; it is of type EventTarget

conclusion

Can’t think of anything else, think of to add

Ts comes with some generic tools, such as Omit and Pick, that can be helpful when it comes to development. Check out my previous review

Finally, I wish you all good health and smooth work!


Sadly, TSX doesn’t even have code highlighting. Prismjs works, but highlightJS doesn’t