Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 16.8 Hook Type Definitions #14722

Closed
pspeter3 opened this issue Jan 29, 2019 · 11 comments
Closed

React 16.8 Hook Type Definitions #14722

pspeter3 opened this issue Jan 29, 2019 · 11 comments

Comments

@pspeter3
Copy link

Do you want to request a feature or report a bug? Feature

What is the current behavior? The type definitions in DefinitelyTyped support hooks but may be out of date DefinitelyTyped/DefinitelyTyped#30057

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

What is the expected behavior? The type definitions align with the API that will be released.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React? 16.8.

@gaearon
Copy link
Collaborator

gaearon commented Jan 29, 2019

Do they already have useDebugValue?

@pspeter3
Copy link
Author

No, these are the implemented types https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L764-L910

//
// React Hooks
// ----------------------------------------------------------------------

// based on the code in https://github.com/facebook/react/pull/13968

// Unlike the class component setState, the updates are not allowed to be partial
type SetStateAction<S> = S | ((prevState: S) => S);
// this technically does accept a second argument, but it's already under a deprecation warning
// and it's not even released so probably better to not define it.
type Dispatch<A> = (value: A) => void;
// Unlike redux, the actions _can_ be anything
type Reducer<S, A> = (prevState: S, action: A) => S;
// 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>;

// 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
// return anything besides `void` or a callback. Async effects need to call an async function inside
// them.
type EffectCallback = () => void | (() => void);

interface MutableRefObject<T> {
  current: T;
}

// This will technically work if you give a Consumer<T> or Provider<T> but it's deprecated and warns
/**
 * 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
 * @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
 * @see https://reactjs.org/docs/hooks-reference.html#usestate
 */
function useState<S>(
  initialState: S | (() => S)
): [S, Dispatch<SetStateAction<S>>];
/**
 * 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 experimental
 * @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>];
/**
 * `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.
 *
 * 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
 * @see https://reactjs.org/docs/hooks-reference.html#useref
 */
// TODO (TypeScript 3.0): <T extends unknown>
function useRef<T>(initialValue: T): MutableRefObject<T>;
// convenience overload for refs given as a ref prop as they typically start with a null value
/**
 * `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.
 *
 * 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.
 *
 * Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type
 * of the generic argument.
 *
 * @version experimental
 * @see https://reactjs.org/docs/hooks-reference.html#useref
 */
// TODO (TypeScript 3.0): <T extends unknown>
function useRef<T>(initialValue: T | null): RefObject<T>;
/**
 * The signature is identical to `useEffect`, but it fires synchronously after all DOM mutations.
 * Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside
 * `useLayoutEffect` will be flushed synchronously, before the browser has a chance to paint.
 *
 * Prefer the standard `useEffect` when possible to avoid blocking visual updates.
 *
 * If you’re migrating code from a class component, `useLayoutEffect` fires in the same phase as
 * `componentDidMount` and `componentDidUpdate`.
 *
 * @version experimental
 * @see https://reactjs.org/docs/hooks-reference.html#uselayouteffect
 */
function useLayoutEffect(
  effect: EffectCallback,
  inputs?: InputIdentityList
): 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.
 *
 * @version experimental
 * @see https://reactjs.org/docs/hooks-reference.html#useeffect
 */
function useEffect(effect: EffectCallback, inputs?: InputIdentityList): void;
// NOTE: this does not accept strings, but this will have to be fixed by removing strings from type Ref<T>
/**
 * `useImperativeMethods` customizes the instance value that is exposed to parent components when using
 * `ref`. As always, imperative code using refs should be avoided in most cases.
 *
 * `useImperativeMethods` should be used with `React.forwardRef`.
 *
 * @version experimental
 * @see https://reactjs.org/docs/hooks-reference.html#useimperativemethods
 */
function useImperativeMethods<T, R extends T>(
  ref: Ref<T> | undefined,
  init: () => R,
  inputs?: InputIdentityList
): 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
 * @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;
/**
 * `useMemo` will only recompute the memoized value when one of the `inputs` has changed.
 *
 * Usage note: if calling `useMemo` with a referentially stable function, also give it as the input in
 * the second argument.
 *
 * ```ts
 * function expensive () { ... }
 *
 * function Component () {
 *   const expensiveResult = useMemo(expensive, [expensive])
 *   return ...
 * }
 * ```
 *
 * @version experimental
 * @see https://reactjs.org/docs/hooks-reference.html#usememo
 */
function useMemo<T>(factory: () => T, inputs: InputIdentityList): T;

@milesj
Copy link
Contributor

milesj commented Jan 29, 2019

@pspeter3 The React team doesn't manage the types. It's best to report it on DefinitelyTyped.

@pspeter3
Copy link
Author

@milesj agreed. Commenting here at the request of @gaearon (https://twitter.com/dan_abramov/status/1090390902869278721). I will submit a PR to DefinitelyTyped for the correct types after ensuring the final API is correct.

@gaearon
Copy link
Collaborator

gaearon commented Jan 29, 2019

Last attempt was here DefinitelyTyped/DefinitelyTyped#32144 (comment)

Looks like it slipped.

There’s also upcoming useReducer change that I’ll comment later about tomorrow.

@gaearon
Copy link
Collaborator

gaearon commented Jan 30, 2019

Reducer API change: #14723

@gaearon
Copy link
Collaborator

gaearon commented Jan 30, 2019

Also #14119 (review)

@Jessidhia
Copy link
Contributor

Jessidhia commented Jan 31, 2019

The latter I implemented directly into the types since the first time around, as it felt like a misuse to be allowed to return anything else.

It also had the side-effect of banning Promise return values, which was a source of much consternation by people until you finally added the runtime warning that I could point to as the source of truth 😇

Q: should the destructor function also be restricted to only returning nothing? I could get the same effect by restricting its return type to void | undefined. It feels like the right thing to do.

@gaearon
Copy link
Collaborator

gaearon commented Jan 31, 2019

Yeah I think it’s reasonable to restrict it too.

@pspeter3
Copy link
Author

@Jessidhia do you have a canonical branch I should help out with somewhere?

@gaearon
Copy link
Collaborator

gaearon commented Feb 8, 2019

Seems like it's done

@gaearon gaearon closed this as completed Feb 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants