Flow: React Class context type not inferred from `static contextType`

Created on 13 Nov 2018  路  10Comments  路  Source: facebook/flow

The newly added Class.contextType feature added to React makes it easier to bind a single context to class components.

But it seems that the type of the context value isn't inferred on this.context in the class instance. Is this know and are there plans to support this?

Try Flow example

import { Component, createContext } from 'react';

type MyContextVal = {
  user: { name: string }
}

const MyContext = createContext<MyContextVal>({
  user: { name: 'Guest' }
})

class MyComponent extends Component<{}> {
  // Expected this line to infer MyContext's type into this.context.
  // Instead, this.context is seen as `any`.
  static contextType = MyContext;

  // Uncomment this line to let Flow know this.context.name doesn't.exist.
  //context: MyContextVal;

  render() {
    return `Hi ${this.context.name}!`
  }
}

Thanks!

react

Most helpful comment

I'm currently working on React types and can look further into this.

All 10 comments

I'm currently working on React types and can look further into this.

Would really appreciate it, @jbrown215. Happy holidays!

@jbrown215 is there any known workaround to have some type coverage for this?

@marioestrada You can declare context as an instance property with the type of your context. See the context: MyContextVal commented line in my initial post.

I'm not planning to add built-in support for this, unless the React community rejects hooks. To me, it seems like function components are the future and that I should focus my work on React types to be around function components.

@jbrown215 perhaps that's an OK approach for greenfield projects.

But one of the big benefits of Flow is being able to adopt it in an existing project, and existing projects probably have a lot of class components that work fine and don't need to be rewritten.

From the Hooks docs:

We intend for Hooks to cover all existing use cases for classes, but we will keep supporting class components for the foreseeable future. At Facebook, we have tens of thousands of components written as classes, and we have absolutely no plans to rewrite them. Instead, we are starting to use Hooks in the new code side by side with classes.

@dmnd: That's true, but I also have to prioritize what I work on to make sure I'm doing the most important work I can be doing. Right now, stronger built in support for static contextType is not the most important thing I can do.

Any idea why this can't be done with libdefs?

import * as React from 'react'

declare class FakeComponent<Props, State> {
  static +contextType?: React$Context<any>
  +context: mixed
}

class A extends FakeComponent<{||}, {||}> {
  static contextType = React.createContext(1)
  context: number
  render() {
        this.context // number, ok
    A.contextType // type is React$Context<any | number>, not React$Context<number>
  }
}

It works with React$Context<*> instead of React$Context<any> tho, but it is deprecated :

Thanks for all your work on Flow, @jbrown215.

I understand one must always prioritize, it's just a bit disappointing that Flow doesn't have enough resources to aim for full support for React. Maybe you could add the label Accepting PRs?

Also ran in to this! My solution was to type both the static contextType value and the context property itself.

something like this:

// file1 where context is defined
const myContext: React.Context<number> = React.createContext(0);
export {myContext};
// file2 where context is consumed
import {myContext} from 'file1'; 

type Context = number;

class ClassName extends React.Component<Props, State> {
  static contextType: React.Context<Context> = myContext;
  context: Context;

  render() {
    const myValue = this.context; 
    ...
  }
}

Typing contextType as React.Context in file2 checks against the type of the exported myContext in file1. Without this type, the type of myContext could change in file1 and would not be caught in file2.

Typing context: Context in file2 allows the usage of myValue in the render function to flow check.

Aliasing the expected value from the context as type Context = number at the top of file2 ensures that context and the value provided by contextType are the same.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ctrlplusb picture ctrlplusb  路  3Comments

mjj2000 picture mjj2000  路  3Comments

john-gold picture john-gold  路  3Comments

funtaps picture funtaps  路  3Comments

pelotom picture pelotom  路  3Comments