Skip to content

Statically typing cells? #2205

@corbt

Description

@corbt

Hey everyone!

I had a proposal on statically typing cells, and would love feedback. I know there are a lot of tradeoffs involved and other folks have been thinking about this!

Essentially, my proposal involves making withCellHOC part of the public API and letting users explicitly call it to create cell components. There would need to be a few modifications to withCellHOC for full typing support -- most importantly, it should be possible to tell it which props the cell expects. A basic sketch of the updated type signature would look something like this. (Note that I've renamed withCellHOC to createCell since I think that's a clearer name.)

type CreateCellArgs<CellProps> = {
  QUERY: DocumentNode | ((variables: Record<string, unknown>) => DocumentNode)
  Success: React.FC<CellProps & Omit<OperationResult, "error" | "loading" | "data">>;
  Failure?: React.Component<CellProps & Omit<OperationResult, "error" | "loading" | "data">>;
  // ...etc
};

export default function createCell<CellProps>(args: CreateCellArgs<CellProps>): React.FC {
  // current contents of withCellHOC go here
}

Consider the following cell, adapted from the tutorial:

export const QUERY = gql`
  query CommentsQuery($postId: Int!) {
    comments(postId: $postId) {
    // ...
    }
  }
`

export const Loading = () => <div>Loading...</div>
export const Empty = () => <div>No comments yet</div>
export const Failure = ({ error }) => <div>Error: {error.message}</div>

export const Success = ({ comments }) =>
  comments.map((comment) => <Comment key={comment.id} comment={comment} />)

The same cell using createCell would be defined as follows:

const QUERY = gql`
  query CommentsQuery($postId: Int!) {
    comments(postId: $postId) {
    // ...
    }
  }
`

const Loading = () => <div>Loading...</div>
const Empty = () => <div>No comments yet</div>
const Failure = ({ error }) => <div>Error: {error.message}</div>

const Success = ({ comments }) =>
  comments.map((comment) => <Comment key={comment.id} comment={comment} />)

// New line here:
export default withCell<{ postId: int }>({ QUERY, Success, Failure, Empty, Loading })

This does add one line of code, of course. But in return, cells and their props can be strongly typed, which is a big win!

This also doesn't have to be mutually exclusive with the existing export const ... syntax. The babel transform could just check whether there's a default export, and skip applying itself in that case.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions