Definitelytyped: React 16.7.0-alpha: Hooks API not possible to test.

Created on 26 Oct 2018  路  15Comments  路  Source: DefinitelyTyped/DefinitelyTyped

Testing the latest hooks API being proposed in React @ 16.7.0-alpha doesn't appear to be possible currently.

  • [x] I tried using the @types/xxxx package and had problems.
  • [x] I tried using the latest stable version of tsc. https://www.npmjs.com/package/typescript
  • [x] I have a question that is inappropriate for StackOverflow. (Please ask any appropriate questions there).
  • [x] [Mention](https://github.com/blog/821-mention-somebody-they-re-notified) the authors (see Definitions by: in index.d.ts) so they can respond.

    • Authors: @johnnyreilly @bbenezech @pzavolinsky @digiguru @ericanderson @morcerf @tkrotoff @DovydasNavickas @onigoetz @theruther4d @guilhermehubner @ferdaber @jrakotoharisoa @pascaloliv @Hotell @franklixuefei

Most helpful comment

Here鈥檚 a full react.d.ts file you can use which adds types for all the new 16.6 and 16.7 features, including hooks:

import * as React from 'react';

declare module 'react' {
  // React 16.6

  function memo<Props>(component: React.StatelessComponent<Props>): React.StatelessComponent<Props>;

  function lazy<P, Component extends React.ComponentType<P>>(
    importFn: () => Promise<Component | {default: Component}>,
  ): Component;

  const Suspense: React.ComponentType<{fallback?: React.ReactNode}>;

  // React 16.7

  type StateUpdateFunction<State> = (newState: State | ((oldState: State) => State)) => void;

  function useState<State>(
    initialState: State | (() => State),
  ): [State, StateUpdateFunction<State>];

 function useEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;
  function useMutationEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;
  function useLayoutEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;

  function useContext<Context>(context: React.Context<Context>): Context;

  type Reducer<State, Action> = (state: State, action: Action) => State;
  function useReducer<State, Action>(
    reducer: Reducer<State, Action>,
    initialState: State,
    initialAction?: Action,
  ): [State, (action: Action) => void];

  function useCallback<Callback extends Function, R>(f: Callback, keys?: any[]): Callback;
  function useMemo<Value>(f: () => Value, keys?: any[]): Value;

  function useRef<T>(): {current: T | null};
  function useRef<T>(initial: T): {current: T};

  function useImperativeMethods<Ref, ImperativeMethods>(
    ref: React.Ref<Ref> | undefined,
    f: () => ImperativeMethods,
    keys?: any[],
  ): void;
}

I鈥檝e tested (most of) these features on a fairly large codebase, but please do let me know if something can be improved.

All 15 comments

is there any update ? about this issue @InquisitiveDevelopment

I have not heard anything and I unfortunately don't have the skills to competently update the definitions file. While testing I have been able to do something like...

const [value, setValue] = (React as any).useState("");

This does effectively disable TS, but does allow you to play with the new API!

Well, for now, you can create typings.d.ts in project's root with the following code:

import React from 'react';

declare module 'react' {
  function useState<T>(defaultValue: T): [T, (newValue: T) => void];
}

Then, import { useState } from 'react' will work.

Later, when we update the typings, you will just delete it and everything will work. (Assuming that types will be similar)

Disclaimer: I didn't try it, you will probably need to update it to align it with real types.

Here鈥檚 a full react.d.ts file you can use which adds types for all the new 16.6 and 16.7 features, including hooks:

import * as React from 'react';

declare module 'react' {
  // React 16.6

  function memo<Props>(component: React.StatelessComponent<Props>): React.StatelessComponent<Props>;

  function lazy<P, Component extends React.ComponentType<P>>(
    importFn: () => Promise<Component | {default: Component}>,
  ): Component;

  const Suspense: React.ComponentType<{fallback?: React.ReactNode}>;

  // React 16.7

  type StateUpdateFunction<State> = (newState: State | ((oldState: State) => State)) => void;

  function useState<State>(
    initialState: State | (() => State),
  ): [State, StateUpdateFunction<State>];

 function useEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;
  function useMutationEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;
  function useLayoutEffect(
    f: () => void | Promise<void> | (() => void | Promise<void>),
    keys?: any[],
  ): void;

  function useContext<Context>(context: React.Context<Context>): Context;

  type Reducer<State, Action> = (state: State, action: Action) => State;
  function useReducer<State, Action>(
    reducer: Reducer<State, Action>,
    initialState: State,
    initialAction?: Action,
  ): [State, (action: Action) => void];

  function useCallback<Callback extends Function, R>(f: Callback, keys?: any[]): Callback;
  function useMemo<Value>(f: () => Value, keys?: any[]): Value;

  function useRef<T>(): {current: T | null};
  function useRef<T>(initial: T): {current: T};

  function useImperativeMethods<Ref, ImperativeMethods>(
    ref: React.Ref<Ref> | undefined,
    f: () => ImperativeMethods,
    keys?: any[],
  ): void;
}

I鈥檝e tested (most of) these features on a fairly large codebase, but please do let me know if something can be improved.

@steadicat thanks for the full def. I believe the lazy signature should accept { default: Component } too. Something like this?:

  function lazy<P, Component extends React.ComponentType<P>>(
    importFn: () => Promise<{ default: Component } | Component>
  ): Component;

Thanks @eknkc. Updated.

@steadicat The useEffect should not be expecting void as a return value, but unknown instead. This because of the async/await which would produce Promise return type.

@FredyC what about void | Promise<void> instead of unknown?

That would work too of course, but why so specific? As I already said here, I don't see a point of keeping this TS2.0 compatible.

My intent was to protect people from accidentally returning some invalid value, expecting it to mean something. The useEffect API expects a cleanup function, or nothing. I can鈥檛 think of a reason why anyone would intentionally return something else, other than they made a mistake, or misunderstood the API. Are you thinking of the case where you want to reuse a function defined elsewhere for a different purpose? In that case I鈥檇 rather be explicit and do () => { otherFunc(); }.

thanks @steadicat

This works great, thank you very much @steadicat! Really looking forward to this being officially released.

I created a small repo using CRA 2.1 with TypeScript support and added these typings, also added some experimental mobx-react support from a prototype made by @mweststrate if anyone wants to play around with React Hooks, MobX and TypeScript support today (needed this for a tech talk at work).

Repo link:
https://github.com/johot/create-react-app-2-typescript-react-hooks-mobx

@steadicat another addition, Suspense receives a maxDuration prop:

const Suspense: React.ComponentType<{ fallback?: React.ReactNode; maxDuration?: number }>;

Um, why are we making these types here when there is a pending PR? There is a bunch of comments there already and doesn't feel much effective to have such two camps discussing it.

Should this issue be closed? Seems like this was resolved.

Was this page helpful?
0 / 5 - 0 ratings