Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix typings for DropTarget and DragSource decorators #1134

Merged
merged 12 commits into from Nov 6, 2018
Merged

Fix typings for DropTarget and DragSource decorators #1134

merged 12 commits into from Nov 6, 2018

Conversation

jeanfortheweb
Copy link
Contributor

The decorator function has to take a component accepting both, props and collected props - but it should return a component which only takes the own props

The decorator function has to take a component accepting both, props and collected props - but it should return a component which only takes the own props
Same fix as for the DropTarget decorator
@jeanfortheweb jeanfortheweb changed the title Fix typings for DropTarget decorator Fix typings for DropTarget and DragSource decorators Sep 17, 2018
@jeanfortheweb
Copy link
Contributor Author

Same goes now for the DragSource decorator

Copy link

@lukyth lukyth left a comment

Choose a reason for hiding this comment

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

Is there anything I can help to get this merged? I also face this issue and really want it to be solved.

| React.ComponentClass<Props>
| React.StatelessComponent<Props>
>(DecoratedComponent: TargetClass): TargetClass & DndComponentClass<Props> {
return function decorateSource(DecoratedComponent: React.ComponentType<Props & CollectedProps>): DndComponentClass<Props> {
Copy link

Choose a reason for hiding this comment

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

TargetClass can't be omitted in the returned value because properties in that class would be lost. So I think it should be:

return function decorateSource<TargetClass extends React.ComponentType<Props & CollectedProps>>(DecoratedComponent: TargetClass): TargetClass & DndComponentClass<Props> {

I've tested this in my own project and everything work fine. TBH, I'm not sure why I don't have to pass CollectedProps to the result of this 😅

The code below doesn't give any type error. Notice that I don't have to pass connectDragSource and isDragging when I use ProjectBoxDragContainer. I also don't lose type of ProjectBoxDragContainer.test.

const projectSource = {
  beginDrag(props: IProjectBoxProps) {
    return { projectId: props.projectId }
  },
}

function collect(connect: DragSourceConnector, monitor: DragSourceMonitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging(),
  }
}

class ProjectBoxDragContainer extends React.PureComponent<{
  isDragging: boolean
  connectDragSource: ConnectDragSource
} & IProjectBoxProps> {
  public static test = '1'
  public render() {
    return this.props.connectDragSource(
      <div style={{ opacity: this.props.isDragging ? 0 : 1 }}>
        <ProjectBox width={this.props.width} projectId={this.props.projectId} />
      </div>
    )
  }
}

export default DragSource('project', projectSource, collect)(ProjectBoxDragContainer)

// Usage
<ProjectBoxDragContainer
  width={ProjectBoxDragContainer.test}
  projectId={p.id}
/>

@darthtrevino
Copy link
Member

Taking a look

@darthtrevino
Copy link
Member

darthtrevino commented Oct 29, 2018

@jeanfortheweb @lukyth Can you guys check out the latest version on this branch? I think the types make sense, but I'd like your input

edit: ugh, types

Copy link

@lukyth lukyth left a comment

Choose a reason for hiding this comment

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

Tested and everything works fine. Just one more comment which is totally optional.

DecoratedComponent,
DecoratedComponent: (DecoratedComponent as any) as React.ComponentType<
Props
>,
Copy link

Choose a reason for hiding this comment

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

How about instead of casting type here, we make DecoratedComponent in decorateHandler to be TargetClass? i.e. lukyth@b101a83

Copy link
Member

Choose a reason for hiding this comment

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

Are you using Functions instead of Decorators in your code? I can make this work with using DragSource and DropTarget as functions, but the types with Decorators gets funky.

To make the API work like @jeanfortheweb wants, we need to exclude props that may be collected from the component interface, so the return type will be a React.ComponentType, excluding collected ones.

That's nice for clients, and it cleans up some concerns about null checking since we can put the collected props in a more rigid interface without optional attributes.

The problem comes when we try to use decorators, Decorators need the original type information to be part of the resultant type (at least that's what I gather from the errors I'm getting).

So if we make this change, it will break types for people who use DragSource and DropTarget as decorators. Not super ideal.

I'd be happy to look at other suggestions on fixing this, but the examples need to compile as-is with decorators for now.

Now, keep in mind that when React 16.7 drops, we will probably rethink this API entirely with hooks, and eliminate the decorator component pattern.

Copy link

Choose a reason for hiding this comment

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

I just notice the problem with decorator since I'm always using it as a function. I tried many ways and nothing works. With the current TypeScript (at least while Request: Class Decorator Mutation issue is still open), I don't think we can solve this omitting props issue in decorator, or even solving it only for the function usage without breaking the decorator.

So.. maybe we have to live with this for now? 😞

Copy link
Member

Choose a reason for hiding this comment

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

Maybe - one option could be to discontinue decorator support in TS. The API would work the same in JS, but you'd need to use function-based decorators for strong typings.

But honestly, I think it would make more sense to think about how the hooks-based API will look instead.

Copy link

Choose a reason for hiding this comment

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

Then for this PR, can we change the example code to use function-based decorators and make the type definition omit collected props in that use case? The hooks-based API will probably be better to discuss in its own issue.

This is a WIP - the TS decorators in examples are broken
@darthtrevino
Copy link
Member

darthtrevino commented Nov 6, 2018 via email

@darthtrevino darthtrevino self-assigned this Nov 6, 2018
This allows us to perform typescript validation on the examples outside of the Gatsby site, which uses babel and misses some issues.

Unit tests for the examples will eventually land here as well.

Ultimately, the text portion of these examples will go back into Gatsby as Markdown, including the functional example as a custom component.
@darthtrevino darthtrevino merged commit b0364b1 into react-dnd:master Nov 6, 2018
@lukyth
Copy link

lukyth commented Nov 7, 2018

I was planned to help you with the example migration at first but you already got it all done 😮 That's a whole lot of work you did there. Thank you so much for your afford! 🙇

darthtrevino pushed a commit that referenced this pull request Feb 3, 2022
* Fix typings for DropTarget decorator

The decorator function has to take a component accepting both, props and collected props - but it should return a component which only takes the own props

* Fix typings for the DragSource decorator

Same fix as for the DropTarget decorator

* fix: correct typings in PR

* fix: correct typings due to types issues in docs

* refactor: update pr with typings per @lukyth suggestions

This is a WIP - the TS decorators in examples are broken

* docs: move documentation examples into a separate package

This allows us to perform typescript validation on the examples outside of the Gatsby site, which uses babel and misses some issues.

Unit tests for the examples will eventually land here as well.

Ultimately, the text portion of these examples will go back into Gatsby as Markdown, including the functional example as a custom component.

* docs: wire up the example pages to use the examples package

* docs: upgrade typescript, correct ts issue in examples

* docs: get docsite running
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants