0
votes

When I export the Room component with connect, in the App component, the ref of the Room component setting does not work normally. If the connect is removed, it works normally. The following is a part of the main code demonstration.``

App.tsx

.....
class App extends React.Component<I_PROPS, I_STATE>{
  private refRoom: React.RefObject<Room_T>;
  constructor(props:any){
     super(props);
     this.refRoom = createRef();
  }
  render() {
    return (
      <Provider store={STORE}>
          <Room ref={this.refRoom} />
       </Provider>
    )
  }
}
export default App;

``

<Room ref={this.refRoom} />

Error: Type 'RefObject<Room_T>' is not assignable to type 'string | ((instance: typeof Room_T | null) => void) | RefObject | null | undefined'. Type 'RefObject<Room_T>' is not assignable to type 'RefObject'. Types of property 'current' are incompatible. Type 'Room_T | null' is not assignable to type 'typeof Room_T | null'. Property 'prototype' is missing in type 'Room_T' but required in type 'typeof Room_T'

Room.tsx

....
import { connect } from 'react-redux';
....
export class Room_T extends React.Component {
    render() {
        return(
            ....
        )
    }
}
export default connect(mapStateToProps, null, null, {
    forwardRef: true
})(Room_T)
dependencies
    react        = "16.13.1"
    react-redux  = "7.2.1"
    redux        = "4.0.5"
devDependencies
    @types/react       = "16.9.26"
    @types/react-redux = "7.1.8"
    typescript         = "3.9.2"
1

1 Answers

0
votes

This has to do with how classes can also be used as types, but consts can't. When you export just the base class (without the connect statement), your refRoom: React.RefObject<Room_T>; is valid, as Room_T refers to a class.

However, when you export a connected component, this is no longer a class, and hence cannot be used as a type. Instead you want to use the typeof operator to get the actual type like React.RefObject<typeof Room_T>;

Hopefully this snippet explains this a bit better:

type I_PROPS = object
type I_STATE = object

class UnconnectedRoom extends React.Component {
  render() {
    return null
  }
  someMethod() {
    console.log('called method')
  }
}

const ConnectedRoom = connect(
  () => {},
  null,
  (stateProps, dispatchProps) => ({}),
  {
    forwardRef: true,
  }
)(UnconnectedRoom)
class App extends React.Component<I_PROPS, I_STATE> {
  constructor(props: any) {
    super(props)
    this.connectedRoomRef = createRef()
    this.unconnectedRoomRef = createRef()
  }

  render() {
    console.log(this.unconnectedRoomRef.current?.someMethod())
    console.log(this.connectedRoomRef.current?.someMethod())
    return (
      <Provider store={{}}>
        <ConnectedRoom ref={this.connectedRoomRef} />
        <UnconnectedRoom ref={this.unconnectedRoomRef} />
      </Provider>
    )
  }
  private connectedRoomRef: React.RefObject<typeof ConnectedRoom> // This is not a class and hence we're using the `typeof` operator
  private unconnectedRoomRef: React.RefObject<UnconnectedRoom> // This is a class and can also be used as a type
}