Repository: TypeScript
Issue: React: enforce correct usage of refs
Labels: Suggestion,Needs Proposal

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Please read the FAQ first, especially the "Common Feature Requests" section.

-->

Potentially a use case for #12936 

>  if you have a problem and you think exact types are the right solution,  please describe the original problem here

https://github.com/microsoft/TypeScript/issues/12936#issuecomment-284590083

## Search Terms

react refs exact type

## Suggestion

In React, it's fairly common to use [refs](https://reactjs.org/docs/refs-and-the-dom.html). This involves creating an object of a specific type, and then passing that value as a prop to a component, which will mutate/reassign its `current` property.

Currently it seem there is no way to use refs in a type safe way. They can be accidentally passed to the wrong component, and there will be no type error.

https://stackoverflow.com/questions/56378639/typescript-react-enforce-correct-ref-props

``` tsx
import * as React from 'react';

class Modal extends React.Component<{}> {
    close = () => {};
}

declare const modal: Modal;

modal.close();

const modalRef = React.createRef<Modal>();

// Let's try giving this ref to the correct component…
// No error as expected :-)
<Modal ref={modalRef} />;

class SomeOtherComponent extends React.Component<{}> {}

// Let's try giving this ref to the wrong component…
// Expected type error but got none! :-(
<SomeOtherComponent ref={modalRef} />;
```

IIUC, this is because `ref={modalRef}` is equivalent to:

``` ts
declare let ref: { current: {} };
declare let modalRef: { current: { close: () => void } };
ref = modalRef;
```

… which will correctly not error, because `modalRef` is a subtype of the target type `ref`.

However, when we're passing a ref to a component, we want to make sure the `ref` argument value (`modalRef`) is a _supertype_, or exact match, of the parameter type (`ref`).

This is because the component is responsible for mutating the ref's `current` property—if we pass in a ref of the wrong type, it will be mutated to something else. Later, when we try to use the ref's `current` value, the value will not match the type:

``` tsx
// Now when we try to use this ref, TypeScript tells us it's safe to do so.
// But it's not, because the ref has been incorrectly assigned to another component!
if (modalRef.current !== null) {
    modalRef.current.close(); // runtime error!
}
```

I am looking for a way to catch these mistakes at compile time, with TypeScript.

Note if the target component is a subtype of `React.Component`, we will get errors as desired:

``` ts
class SomeOtherComponent extends React.Component<{}> {
    foo = () => {}
}

// Let's try giving this ref to the wrong component…
// We got an error :-)
<SomeOtherComponent ref={modalRef} />;
```

## Checklist

My suggestion meets these guidelines:

* [ ] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).