Skip to content

Instantly share code, notes, and snippets.

@jdthorpe
Last active August 8, 2018 05:02
Show Gist options
  • Save jdthorpe/d0d417b66e4ef5554f805824ebdc7246 to your computer and use it in GitHub Desktop.
Save jdthorpe/d0d417b66e4ef5554f805824ebdc7246 to your computer and use it in GitHub Desktop.
Better Typings for react-dnd

The standard typings for react-dnd suck. In particular

  • They ignore the fact that thre props recieved by the wrapped component are a union of the props passed in to the react-dnd HOC and props collected by react-dnd collectors
  • Items are assigned type Object
  • DropResults are assigned the type Object

These types are a work and progress, which means they suck too. They just suck a little less than the standard typings

// Type definitions for React DnD v2.0.2
// Project: https://github.com/gaearon/react-dnd
// Definitions by: Asana <https://asana.com>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.6
///<reference types="react" />
declare module __ReactDnd {
// Decorated React Components
// ----------------------------------------------------------------------
class ContextComponent<P, S> extends React.Component<P, S> {
getDecoratedComponentInstance(): React.Component<P, S>;
// Note: getManager is not yet documented on the React DnD docs.
getManager(): any;
}
class DndComponent<P, S> extends React.Component<P, S> {
getDecoratedComponentInstance(): React.Component<P, S>;
getHandlerId(): Identifier;
}
interface ContextComponentClass<P> extends React.ComponentClass<P> {
new(props?: P, context?: any): ContextComponent<P, any>;
DecoratedComponent: React.ComponentClass<P>;
}
interface DndComponentClass<P> extends React.ComponentClass<P> {
new(props?: P, context?: any): DndComponent<P, any>;
DecoratedComponent: React.ComponentClass<P>;
}
// Top-level API
// ----------------------------------------------------------------------
export function DragSource</* outside props */P,
/* collected props */C,
/* item interface */T=any>(
type: Identifier | ((props: P) => Identifier),
spec: DragSourceSpec<P,T>,
collect: DragSourceCollector<C>,
options?: DndOptions<P>
): (componentClass: React.ComponentClass<P & C> | React.StatelessComponent<P & C>) => DndComponentClass<P>;
export function DropTarget</* outside props */ P,
/* collected props */ C=any,
/* item interface */ T=any >(
types: Identifier | Identifier[] | ((props: P) => Identifier | Identifier[]),
spec: DropTargetSpec<P,T>,
collect: DropTargetCollector<C>,
options?: DndOptions<P>
): (componentClass: React.ComponentClass<P & C> | React.StatelessComponent<P & C>) => DndComponentClass<P>;
export function DragDropContext<P>(
backend: Backend
): <P>(componentClass: React.ComponentClass<P> | React.StatelessComponent<P>) => ContextComponentClass<P>;
interface DragDropContextProviderProps {
backend: Backend,
window?: Window,
}
export class DragDropContextProvider extends React.Component<DragDropContextProviderProps> {
}
export function DragLayer<P>(
collect: DragLayerCollector<P>,
options?: DndOptions<P>
): (componentClass: React.ComponentClass<P> | React.StatelessComponent<P>) => DndComponentClass<P>;
export type DragSourceCollector<C> = (connect: DragSourceConnector, monitor: DragSourceMonitor) => C;
export type DropTargetCollector<C> = (connect: DropTargetConnector, monitor: DropTargetMonitor) => C;
export type DragLayerCollector<T> = (monitor: DragLayerMonitor) => T;
// Shared
// ----------------------------------------------------------------------
// The React DnD docs say that this can also be the ES6 Symbol.
type Identifier = string;
interface ClientOffset {
x: number;
y: number;
}
interface DndOptions<P> {
arePropsEqual?(props: P, otherProps: P): boolean;
}
// DragSource
// ----------------------------------------------------------------------
interface DragSourceSpec<P,T=any> {
beginDrag(props: P, monitor?: DragSourceMonitor<T>, component?: React.Component<P>): Object;
endDrag?(props: P, monitor?: DragSourceMonitor<T>, component?: React.Component<P>): void;
canDrag?(props: P, monitor?: DragSourceMonitor<T>): boolean;
isDragging?(props: P, monitor?: DragSourceMonitor<T>): boolean;
}
class DragSourceMonitor<T=any,S=any> {
canDrag(): boolean;
isDragging(): boolean;
getItemType(): Identifier;
getItem(): T;
getDropResult(): S;
didDrop(): boolean;
getInitialClientOffset(): ClientOffset;
getInitialSourceClientOffset(): ClientOffset;
getClientOffset(): ClientOffset;
getDifferenceFromInitialOffset(): ClientOffset;
getSourceClientOffset(): ClientOffset;
}
class DragSourceConnector {
dragSource(): ConnectDragSource;
dragPreview(): ConnectDragPreview;
}
interface DragElementWrapper<O> {
<P>(elementOrNode: React.ReactElement<P>, options?: O): React.ReactElement<P>;
}
interface DragSourceOptions {
dropEffect?: string;
}
interface DragPreviewOptions {
captureDraggingState?: boolean;
anchorX?: number;
anchorY?: number;
offsetX?: number;
offsetY?: number;
}
type ConnectDragSource = DragElementWrapper<DragSourceOptions>;
type ConnectDragPreview = DragElementWrapper<DragPreviewOptions>;
/// DropTarget
// ----------------------------------------------------------------------
interface DropTargetSpec<P,T=any> {
drop?(props: P, monitor?: DropTargetMonitor<T>, component?: React.Component<P>): T|void;
hover?(props: P, monitor?: DropTargetMonitor<T>, component?: React.Component<P>): void;
canDrop?(props: P, monitor?: DropTargetMonitor<T>): boolean;
}
class DropTargetMonitor<T=any,S=any> {
canDrop(): boolean;
isOver(options?: { shallow: boolean }): boolean;
getItemType(): Identifier;
getItem(): T;
getDropResult(): S;
didDrop(): boolean;
getInitialClientOffset(): ClientOffset;
getInitialSourceClientOffset(): ClientOffset;
getClientOffset(): ClientOffset;
getDifferenceFromInitialOffset(): ClientOffset;
getSourceClientOffset(): ClientOffset;
}
class DropTargetConnector {
dropTarget(): ConnectDropTarget;
}
//export type ConnectDropTarget = <P,Q>(elementOrNode: React.ReactElement<P>) => React.ReactElement<P & Q>;
type ConnectDropTarget = <P>(elementOrNode: React.ReactElement<P>) => React.ReactElement<P>;
/// DragLayerMonitor
// ----------------------------------------------------------------------
class DragLayerMonitor {
isDragging(): boolean;
getItemType(): Identifier;
getItem(): Object;
getInitialClientOffset(): ClientOffset;
getInitialSourceClientOffset(): ClientOffset;
getClientOffset(): ClientOffset;
getDifferenceFromInitialOffset(): ClientOffset;
getSourceClientOffset(): ClientOffset;
}
/// Backend
/// ---------------------------------------------------------------------
// TODO: Fill in the Backend interface.
// The React DnD docs do not cover this, and this is only needed for
// creating custom backends (i.e. not using the built-in HTML5Backend).
interface Backend {}
}
declare module "react-dnd" {
export = __ReactDnd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment