typescript2.0mithril.jstsx

TypeScript 2 TSX preserve and noimplicitany error TS2602: the global type 'JSX.Element' does not exist


I'm using TypeScript 2 and TSX with the preserve (not React) setting and with "noImplicitAny" enabled:

"noImplicitAny": true,
"jsx": "preserve"

The problem is, I keep getting this error when trying to build a simple TSX file:

error TS2602: JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist.

Here's an example of my TSX file:

'use strict';

import m from './m';

export default {
  view() {
    return (
      <h1>Hello Mithril!</h1>
    );
  }
};

I'm trying to get TSX working with a non-React stack (Mithril). Thanks in advance!


Solution

  • Answer to original question: (how to solve the TS2602 error)

    This is quite simple, as explained here:

    As the errors say: "because the global type 'JSX.Element' does not exist"

    you can define those types:

    declare namespace JSX {
      interface Element { }
      interface IntrinsicElements { div: any; }
    }
    

    I recommend getting the react-jsx.d.ts file from DefinitelyTyped

    You can use this file as a source for more complete typings (you'll need definitions for every sub-element in IntrinsicElements, i.e. div, p, a, etc.)

    Getting farther with TSX and Mithril:

    Once you've solved the typing issues, you'll find that you're not quite there. If you use the "jsx": "preserve" setting, the HTML code will be written directly in the generated js file, without any translation. This of course can't be loaded by a web browser (because it's a javascript file, not an html file).

    I think there are two ways to make it work:

    First solution that comes to mind is to use "jsx":"react" and write a small wrapper that will forward the calls to mithril, like this:

    class React {
      public static createElement(selector: string, attributes: object, ...children: Mithril.Child[]): Mithril.Child {
        return m(selector, attributes, children);
      }
    }
    

    This is the solution I'm currently using because it doesn't involve additional tools.

    The other solution is to keep "jsx":"preserve" and use Babel, as described in mithril documentation, to translate the jsx file (which is generated by typescript from the tsx file) to a valid js file.

    In the end, I've managed to make it work, but I found the process quite messy, with typescript/npm module system getting in the way to have JSX types extend Mithril types (so that your functions can return mithril-compatible types), etc. I had to modify the mithril typings (and drop npm @types/mithril), and add a few modules of my own.

    I'm interested to know if someone solved this problem in an elegant and simple way!