question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[TypeScript] DragSource component return type expects unneeded props

See original GitHub issue

Describe the bug

When a component is wrapped in DragSource, the return value is a component that expects props to be passed in from a parent, but still expects the props that DragSource is providing itself.

To Reproduce

Simple example:

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { ConnectDragSource, DragSource, DragSourceConnector } from 'react-dnd';

interface OwnProps { name: string; }
interface DragProps { connectDragSource: ConnectDragSource; }

type AllProps = OwnProps & DragProps;

class Foo extends React.Component<AllProps> {
  public render(): JSX.Element {
    return this.props.connectDragSource(
      <div>{this.props.name}</div>
    );
  }
}

function mapDragProps(connect: DragSourceConnector): DragProps {
  return { connectDragSource: connect.dragSource() };
}

const source = {
  beginDrag(props: AllProps): { name: string } {
    return { name: props.name };
  }
};

const DraggableFoo = DragSource('FOO', source, mapDragProps)(Foo);

ReactDOM.render(<DraggableFoo name='dylan' />, document.body);

Expected behavior

Code compiles

Actual behavior

Type '{ name: string; }' is not assignable to type '(IntrinsicAttributes & IntrinsicClassAttributes<Foo> & Readonly<{ children?: ReactNode; }> & Read...'.
  Type '{ name: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<AllProps, ComponentState, any>> & Readon...'.
    Type '{ name: string; }' is not assignable to type 'Readonly<AllProps>'.
      Property 'connectDragSource' is missing in type '{ name: string; }'.

I also tried changing the 2nd-to-last line to:

const DraggableFoo = DragSource('FOO', source, mapDragProps)(Foo) as React.ComponentClass<OwnProps>;

— which fixes the rendering props issue but fails at coercing:

Type 'typeof Foo & DndComponentClass<AllProps>' cannot be converted to type 'ComponentClass<OwnProps>'.
  Types of parameters 'props' and 'props' are incompatible.
    Type 'OwnProps' is not comparable to type 'Readonly<AllProps>'.
      Property 'connectDragSource' is missing in type 'OwnProps'.

Desktop:

  • OS: macOS
  • Version: react 16.4.1, react-dnd 5.0.0

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:10 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
jeanforthewebcommented, Sep 17, 2018

@sebastian-lenz is totally right. Was just here to open a PR myself but checked the tickets before. Would you mind open a PR for this? Same for DropTarget of course.

Edit: NVM, just opened one since it was so simple. Check #1134, should be fine as is. Edit 2: Not that simple. I’ll look into it at a later time, since I fixed it locally for now and have no time unfortunately. But to be honest, there is quiet some space for other improvements (typing DragMonitor to get the actual item type from getItem() for example). Maybe it’s a good idea to gather some type improvements in general.

3reactions
sebastian-lenzcommented, Aug 30, 2018

I stumbled upon the same problem. Looking at DragSource.d.ts I actually don’t understand why both the argument and return type use the same probs. The argument should consume the collected probs next to the external probs?

This is the current definition from https://github.com/react-dnd/react-dnd/blob/master/packages/react-dnd/src/DragSource.ts#L79:

return function decorateSource<
  TargetClass extends
    | React.ComponentClass<Props>
    | React.StatelessComponent<Props>
>(DecoratedComponent: TargetClass): TargetClass & DndComponentClass<Props>

I think it should read something like this:

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

React.ComponentType is just a shorthand for React.ComponentClass<Props> | React.StatelessComponent<Props>. The important bit is appending CollectedProps to the props of the argument.

Read more comments on GitHub >

github_iconTop Results From Across the Web

component which lacks return-type annotation, implicitly has ...
I just want the component to receive an anonymous function with void return type as props and I'm frustrated about this typescript error ......
Read more >
How To Customize React Components with Props
PropTypes are a simple type system to check that data matches the expected types during runtime. They serve as both documentation and an...
Read more >
How to Overload TypeScript React Component Interfaces by ...
This article explains how to create correct, intuitive APIs for React components in TypeScript by using prop values to overload React components.
Read more >
useDrag - React DnD
The useDrag hooks returns a few key items: a set of collected props, and refs that may be attached to drag source and...
Read more >
Best Practices for Using TypeScript and React - OneSignal
The result is a component that is clean and extensible. If additional props are needed, swap the type for an interface : import...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found