KEMBAR78
[RFC] Make all refs mutable by gaearon · Pull Request #64772 · DefinitelyTyped/DefinitelyTyped · GitHub
Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions types/react/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ declare namespace React {
| (new (props: P) => Component<any, any>);

interface RefObject<T> {
readonly current: T | null;
current: T | null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need the concept of a React-managed ref and a user-managed ref. The tests already have this case: const boolRef = useRef(false) and it expects boolRef.current to be a boolean. But with only RefObject boolRef.current will be typed as boolean | null. We're basically saying here that every ref needs to account for the null value even though it might never have that value.

I think for many case you do want to have a bottom value in current. But sometimes you also don't (or want that bottom value to be something other than null).

So I start playing around with moving that | null member to the actual usages i.e. refs created and managed by React will contain T | null but everything else will just be T

}
// Bivariance hack for consistent unsoundness with RefObject
type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
Expand Down Expand Up @@ -541,7 +541,7 @@ declare namespace React {
displayName?: string | undefined;
}

type ForwardedRef<T> = ((instance: T | null) => void) | MutableRefObject<T | null> | null;
type ForwardedRef<T> = ((instance: T | null) => void) | RefObject<T | null> | null;

interface ForwardRefRenderFunction<T, P = {}> {
(props: P, ref: ForwardedRef<T>): ReactElement | null;
Expand Down Expand Up @@ -876,9 +876,9 @@ declare namespace React {
// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
type EffectCallback = () => (void | Destructor);

interface MutableRefObject<T> {
current: T;
}
// These types were previously distinct, but that was not correct: all refs are technically mutable.
// TODO: Remove MutableRefObject completely in a future version.
type MutableRefObject<T> = RefObject<T>;

// This will technically work if you give a Consumer<T> or Provider<T> but it's deprecated and warns
/**
Expand Down Expand Up @@ -1005,7 +1005,7 @@ declare namespace React {
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T): RefObject<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
Expand All @@ -1014,9 +1014,6 @@ 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.
*
* Usage note: if you need the result of useRef to be directly mutable, include `| null` in the type
* of the generic argument.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
Expand All @@ -1033,7 +1030,7 @@ declare namespace React {
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useref
*/
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
function useRef<T = undefined>(): RefObject<T | undefined>;
/**
* 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
Expand Down