mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-07-01 15:50:13 +00:00
[react] Breaking! Update hooks API to (what's expected to be) the final 16.8.0 API (#32659)
* Update hooks API to (what's expected to be) the final 16.8.0 API * Remove unneeded compatibility alias
This commit is contained in:
committed by
John Reilly
parent
59d0d56653
commit
c8477f17f5
98
types/react/index.d.ts
vendored
98
types/react/index.d.ts
vendored
@@ -775,9 +775,13 @@ declare namespace React {
|
||||
type Dispatch<A> = (value: A) => void;
|
||||
// Unlike redux, the actions _can_ be anything
|
||||
type Reducer<S, A> = (prevState: S, action: A) => S;
|
||||
// types used to try and prevent the compiler from reducing S
|
||||
// to a supertype common with the second argument to useReducer()
|
||||
type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;
|
||||
type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;
|
||||
// The identity check is done with the SameValue algorithm (Object.is), which is stricter than ===
|
||||
// TODO (TypeScript 3.0): ReadonlyArray<unknown>
|
||||
type InputIdentityList = ReadonlyArray<any>;
|
||||
type DependencyList = ReadonlyArray<any>;
|
||||
|
||||
// NOTE: Currently, in alpha.0, the effect callbacks are actually allowed to return anything,
|
||||
// but functions are treated specially. The next version published with hooks will warn if you actually
|
||||
@@ -794,14 +798,14 @@ declare namespace React {
|
||||
* Accepts a context object (the value returned from `React.createContext`) and returns the current
|
||||
* context value, as given by the nearest context provider for the given context.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usecontext
|
||||
*/
|
||||
function useContext<T>(context: Context<T>/*, (not public API) observedBits?: number|boolean */): T;
|
||||
/**
|
||||
* Returns a stateful value, and a function to update it.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usestate
|
||||
*/
|
||||
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
|
||||
@@ -812,10 +816,54 @@ declare namespace React {
|
||||
* multiple sub-values. It also lets you optimize performance for components that trigger deep
|
||||
* updates because you can pass `dispatch` down instead of callbacks.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usereducer
|
||||
*/
|
||||
function useReducer<S, A>(reducer: Reducer<S, A>, initialState: S, initialAction?: A | null): [S, Dispatch<A>];
|
||||
// overload where "I" may be a subset of ReducerState<R>; used to provide autocompletion.
|
||||
// If "I" matches ReducerState<R> exactly then the last overload will allow initializer to be ommitted.
|
||||
// the last overload effectively behaves as if the identity function (x => x) is the initializer.
|
||||
function useReducer<R extends Reducer<any, any>, I>(
|
||||
reducer: R,
|
||||
initializerArg: I & ReducerState<R>,
|
||||
initializer: (arg: I & ReducerState<R>) => ReducerState<R>
|
||||
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
|
||||
/**
|
||||
* An alternative to `useState`.
|
||||
*
|
||||
* `useReducer` is usually preferable to `useState` when you have complex state logic that involves
|
||||
* multiple sub-values. It also lets you optimize performance for components that trigger deep
|
||||
* updates because you can pass `dispatch` down instead of callbacks.
|
||||
*
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usereducer
|
||||
*/
|
||||
// overload for free "I"; all goes as long as initializer converts it into "ReducerState<R>".
|
||||
function useReducer<R extends Reducer<any, any>, I>(
|
||||
reducer: R,
|
||||
initializerArg: I,
|
||||
initializer: (arg: I) => ReducerState<R>
|
||||
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
|
||||
/**
|
||||
* An alternative to `useState`.
|
||||
*
|
||||
* `useReducer` is usually preferable to `useState` when you have complex state logic that involves
|
||||
* multiple sub-values. It also lets you optimize performance for components that trigger deep
|
||||
* updates because you can pass `dispatch` down instead of callbacks.
|
||||
*
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usereducer
|
||||
*/
|
||||
// I'm not sure if I keep this 2-ary or if I make it (2,3)-ary; it's currently (2,3)-ary.
|
||||
// The Flow types do have an overload for 3-ary invocation with undefined initializer.
|
||||
// NOTE: the documentation or any alphas aren't updated, this is current for master.
|
||||
// NOTE 2: without the ReducerState indirection, TypeScript would reduce S to be the most common
|
||||
// supertype between the reducer's return type and the initialState (or the initializer's return type),
|
||||
// which would prevent autocompletion from ever working.
|
||||
function useReducer<R extends Reducer<any, any>>(
|
||||
reducer: R,
|
||||
initialState: ReducerState<R>,
|
||||
initializer?: undefined
|
||||
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
|
||||
/**
|
||||
* `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
|
||||
* (`initialValue`). The returned object will persist for the full lifetime of the component.
|
||||
@@ -823,7 +871,7 @@ declare namespace React {
|
||||
* Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
|
||||
* value around similar to how you’d use instance fields in classes.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#useref
|
||||
*/
|
||||
// TODO (TypeScript 3.0): <T extends unknown>
|
||||
@@ -839,7 +887,7 @@ declare namespace React {
|
||||
* Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type
|
||||
* of the generic argument.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#useref
|
||||
*/
|
||||
// TODO (TypeScript 3.0): <T extends unknown>
|
||||
@@ -854,20 +902,20 @@ declare namespace React {
|
||||
* If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as
|
||||
* `componentDidMount` and `componentDidUpdate`.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect
|
||||
*/
|
||||
function useLayoutEffect(effect: EffectCallback, inputs?: InputIdentityList): void;
|
||||
function useLayoutEffect(effect: EffectCallback, deps?: DependencyList): void;
|
||||
/**
|
||||
* Accepts a function that contains imperative, possibly effectful code.
|
||||
*
|
||||
* @param effect Imperative function that can return a cleanup function
|
||||
* @param inputs If present, effect will only activate if the values in the list change.
|
||||
* @param deps If present, effect will only activate if the values in the list change.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#useeffect
|
||||
*/
|
||||
function useEffect(effect: EffectCallback, inputs?: InputIdentityList): void;
|
||||
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
|
||||
// NOTE: this does not accept strings, but this will have to be fixed by removing strings from type Ref<T>
|
||||
/**
|
||||
* `useImperativeHandle` customizes the instance value that is exposed to parent components when using
|
||||
@@ -875,23 +923,23 @@ declare namespace React {
|
||||
*
|
||||
* `useImperativeHandle` should be used with `React.forwardRef`.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#useimperativehandle
|
||||
*/
|
||||
function useImperativeHandle<T, R extends T>(ref: Ref<T>|undefined, init: () => R, inputs?: InputIdentityList): void;
|
||||
function useImperativeHandle<T, R extends T>(ref: Ref<T>|undefined, init: () => R, deps?: DependencyList): void;
|
||||
// I made 'inputs' required here and in useMemo as there's no point to memoizing without the memoization key
|
||||
// useCallback(X) is identical to just using X, useMemo(() => Y) is identical to just using Y.
|
||||
/**
|
||||
* `useCallback` will return a memoized version of the callback that only changes if one of the `inputs`
|
||||
* has changed.
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usecallback
|
||||
*/
|
||||
// TODO (TypeScript 3.0): <T extends (...args: never[]) => unknown>
|
||||
function useCallback<T extends (...args: any[]) => any>(callback: T, inputs: InputIdentityList): T;
|
||||
function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;
|
||||
/**
|
||||
* `useMemo` will only recompute the memoized value when one of the `inputs` has changed.
|
||||
* `useMemo` will only recompute the memoized value when one of the `deps` has changed.
|
||||
*
|
||||
* Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in
|
||||
* the second argument.
|
||||
@@ -905,10 +953,22 @@ declare namespace React {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @version experimental
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usememo
|
||||
*/
|
||||
function useMemo<T>(factory: () => T, inputs: InputIdentityList): T;
|
||||
function useMemo<T>(factory: () => T, deps: DependencyList): T;
|
||||
/**
|
||||
* `useDebugValue` can be used to display a label for custom hooks in React DevTools.
|
||||
*
|
||||
* NOTE: We don’t recommend adding debug values to every custom hook.
|
||||
* It’s most valuable for custom hooks that are part of shared libraries.
|
||||
*
|
||||
* @version 16.8.0
|
||||
* @see https://reactjs.org/docs/hooks-reference.html#usedebugvalue
|
||||
*/
|
||||
// the name of the custom hook is itself derived from the function name at runtime:
|
||||
// it's just the function name without the "use" prefix.
|
||||
function useDebugValue<T>(value: T, format?: (value: T) => any): void;
|
||||
|
||||
//
|
||||
// Event System
|
||||
|
||||
@@ -63,7 +63,13 @@ export function App() {
|
||||
const birthdayRef = React.useRef<FancyButton>(null);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
birthdayRef.current!.fancyClick();
|
||||
if (birthdayRef.current !== null) {
|
||||
birthdayRef.current.fancyClick();
|
||||
} else {
|
||||
// this looks redundant but it ensures the type actually has "null" in it instead of "never"
|
||||
// $ExpectType null
|
||||
birthdayRef.current;
|
||||
}
|
||||
});
|
||||
|
||||
return <>
|
||||
@@ -85,13 +91,22 @@ const context = React.createContext<Context>({ test: true });
|
||||
function useEveryHook(ref: React.Ref<{ id: number }>|undefined): () => boolean {
|
||||
const value: Context = React.useContext(context);
|
||||
const [, setState] = React.useState(() => 0);
|
||||
const [reducerState, dispatch] = React.useReducer(reducer, initialState, { type: 'resetAge' });
|
||||
// Bonus typescript@next version
|
||||
// const [reducerState, dispatch] = React.useReducer(reducer, true as const, arg => arg && initialState);
|
||||
// Compile error in typescript@3.0 but not in typescript@3.1.
|
||||
// const [reducerState, dispatch] = React.useReducer(reducer, true as true, arg => arg && initialState);
|
||||
const [reducerState, dispatch] = React.useReducer(reducer, true as true, (arg: true): AppState => arg && initialState);
|
||||
|
||||
// inline object, to (manually) check if autocomplete works
|
||||
React.useReducer(reducer, { age: 42, name: 'The Answer' });
|
||||
|
||||
// make sure this is not going to the |null overload
|
||||
// $ExpectType MutableRefObject<boolean>
|
||||
const didLayout = React.useRef(false);
|
||||
|
||||
const id = React.useMemo(() => Math.random(), []);
|
||||
React.useImperativeHandle(ref, () => ({ id }), [id]);
|
||||
// was named like this in the first alpha, renamed before release
|
||||
// $ExpectError
|
||||
React.useImperativeMethods(ref, () => ({}), [id]);
|
||||
|
||||
@@ -105,6 +120,9 @@ function useEveryHook(ref: React.Ref<{ id: number }>|undefined): () => boolean {
|
||||
setState(reducerState.age);
|
||||
}, []);
|
||||
|
||||
React.useDebugValue(id, value => value.toFixed());
|
||||
React.useDebugValue(id);
|
||||
|
||||
return React.useCallback(() => didLayout.current, []);
|
||||
}
|
||||
|
||||
@@ -118,5 +136,6 @@ const UsesEveryHook = React.forwardRef(
|
||||
);
|
||||
const everyHookRef = React.createRef<{ id: number }>();
|
||||
<UsesEveryHook ref={everyHookRef}/>;
|
||||
|
||||
// TODO: "implicit any" in typescript@3.0 but not in typescript@3.1
|
||||
// <UsesEveryHook ref={ref => { ref && console.log(ref.id); }}/>;
|
||||
|
||||
Reference in New Issue
Block a user