zilverline / react-tap-event-plugin

Instant TapEvents for React
http://facebook.github.io/react/
MIT License
1.07k stars 110 forks source link

syntax error in Typescript when adding onTouchTap to div #58

Closed HenrikBechmann closed 8 years ago

HenrikBechmann commented 8 years ago

Hello,

Using Typescript, in a .tsx file, after

import injectTapEventPlugin = require('react-tap-event-plugin')
injectTapEventPlugin()

with this JSX:

<div onTouchTap={ this.showFront }>

I get the syntax error:

error TS2339: Property 'onTouchTap' does not exist on type 'HTMLProps<HTMLDivElement>'.

in spite of having

interface HTMLDivElement {

    onTouchTap: Function,

}

in the same code file, which should merge onTouchTap into the HTMLDivElement interface used by div in lib.d.ts

The intellisense is seeing onTouchStart etc, but not onTouchTap.

Is there something wrong, or am I doing something wrong?

Thanks,

lukephills commented 8 years ago

I think this is probably because onTouchTap is an attribute specific to this library. It wont be included in typescript lib or React definition files. In order for you to use this with typescript you should add a definition file and import it.

You might be able do this by casting as a React.DOMAttributes:

<div onTouchStart as React.DOMAttributes={}>
HenrikBechmann commented 8 years ago

Thanks @lukephills. The following worked, placed in my custom material-ui.d.ts custom addon definitions:

declare module __React{
    interface DOMAttributes {
        onTouchTap?: Function,
    }
}

see my stackoverflow question and answers (sort of a group effort)

realyze commented 8 years ago

Hm, I guess React typings have changed since? The snippet above doesn't work for me with TS2 and react bindings from @types/react...

himStone commented 8 years ago

TS2

+1

rlmckenney commented 8 years ago

I am using it successfully with TS2. In the index.tsx rather than import use const ...

const injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();

Then add a custom type definition for require. I created a require.d.ts file in my types dir with

declare var require: {
    (path: string): any;
    <T>(path: string): T;
    (paths: string[], callback: (...modules: any[]) => void): void;
    ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
};

That should do the trick.

realyze commented 8 years ago

@rlmckenney But doesn't your tsc complain that onTouchTap is not a valid attribute when compiling .tsx files?

michaeljones commented 7 years ago

Not a great solution but you can place the props into an object and then destructure them into the element like:

      const props = {
        key: index,
        src: item.data,
        onTouchTap: () => this.handleOpen()
      };

      return (
        <img {...props} />
      );

This seems to dodge the type checker. I only have one instance of this in my code base at the moment but it won't be fun if there are lots. Very happy to hear of a better solution. I can't get the type extension described above to work. I suspect it is because the 'react' types have been re-written to a '@types' approach and are now less extendable in some way? Though I've no idea what I'm talking about really.

ptitmouton commented 7 years ago

This helped me out:


declare module 'react' {
    interface HTMLProps<T> {
        onTouchTap?: React.EventHandler<React.TouchEvent<T>>;
    }
}
HenrikBechmann commented 7 years ago

for TS2 I've been using onClick instead of onTouchTap for intrinsic elements with no problems so far

realyze commented 7 years ago

@ptitmouton When I do that, I'm getting a lot of

error TS2604: JSX element type 'Router' does not have any construct or call signatures

(and other) errors. I'm using @types definitions for react (0.14.41). You don't get any errors?

ptitmouton commented 7 years ago

@realyze Where did you place it? I also have problems declare module 'react' overriding the module instead of extending it. I have put it just underneath injectTapEventPlugin() and that seems to work, though it's not the nicest solution

realyze commented 7 years ago

@ptitmouton Aaah, that works, brilliant, thanks! Looks like I must have missed something about the way Typescript modules work... I somehow thought it shouldn't matter if you extend the module in a d.ts file (or TBH I even thought that that's the correct place to do that :-) )

ptitmouton commented 7 years ago

@realyze Same here. If someone is able to clear this up I'd be very interested.

realyze commented 7 years ago

@ptitmouton FYI, I've opened https://github.com/Microsoft/TypeScript/issues/14325 to figure out what's happening (I'm a curious guy :) ).

Macmee commented 7 years ago

FYI to any newcomers to this, @blakeembrey responded to that ticket ^ and this solution works:

import * as React from 'react';
injectTapEventPlugin();
declare module 'react' {
    interface HTMLProps<T> {
        onTouchTap?: React.EventHandler<React.TouchEvent<T>>;
    }
}

apparently by importing react first, you flip the file into module mode such that your module declaration augments the previous definition for react as opposed to over-writing it.

wcandillon commented 7 years ago

This is how I trick the compiler:

<div {...{onTouchTap: () => alert("onTouchTap")} as {}}>
ReadingSteiner commented 7 years ago

Hey guys, in the latest @types/react, use this solution

import * as React from 'react';
import * as injectTapEventPlugin from 'react-tap-event-plugin'
injectTapEventPlugin()
declare module 'react' {
    interface DOMAttributes<T> {
        onTouchTap?: React.EventHandler<React.TouchEvent<T>>;
    }
}