Skip to content

TS files cannot use JSX components declared as a classes in JS/JSX file #14558

Closed

Description

CC Donatas Petrauskas (@donataswix)

It appears that using a React component written as a class in a .js file causes some issues.

Start a project with the following files:

tsconfig.json

{
  "compilerOptions": {
    "module": "es2015",
    "target": "esnext",
    "jsx": "react-native",
    "strictNullChecks": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "lib": [
      "es5",
      "es6",
      "es7",
      "es2017",
      "dom"
    ],
    "outDir": "dist"
  },
  "include": [
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

index.tsx

import React from 'react';
import Hello from './hello';

class A extends React.Component<void,void> {
  render() {
    return (
      <div>
        <Hello/>
      </div>
    );
  }
}

hello.js

import React from 'react';

export default class Hello extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

Expected: No problems
Actual: Error on <Hello />: JSX element type 'Hello' does not have any construct or call signatures.

Note that if you add type arguments to Component in hello.js, this will actually fix the problem (while creating new ones).

Potentially related is #13609.

Activity

  1. mhegazy commented on Mar 9, 2017

    @mhegazy
    Contributor

    Can you give #14396 a try and see if it fixes the issue?

  2. timothyallan commented on Apr 15, 2017

    @timothyallan

    This is killing me trying to migrate a large project to Typescript. I've got a hundred plain ol React components and I'd love to be able to do 1 at a time, but once converted to .tsx, they can't import any other .js files without this error.

  3. mhegazy commented on Apr 19, 2017

    @mhegazy
    Contributor

    This is addressed by #14907. Tim (@timothyallan) please give typescript@2.3 a try and let us know if you are running into other issues.

  4. robin-anil commented on May 4, 2017

    @robin-anil

    This is not solved with typescript@2.3.2 I am still seeing issues

  5. mhegazy commented on May 5, 2017

    @mhegazy
    Contributor

    I see it working on latest. if you are seeing issues please file a new issue:

    c:\test\14558>type tsconfig.json
    {
      "compilerOptions": {
        "module": "es2015",
        "target": "esnext",
        "jsx": "react-native",
        "strictNullChecks": true,
        "allowSyntheticDefaultImports": true,
        "allowJs": true,
        "checkJs": true,
        "lib": [
          "es5",
          "es6",
          "es7",
          "es2017",
          "dom"
        ],
        "outDir": "dist"
      },
      "include": [
        "**/*.ts",
        "**/*.tsx",
        "**/*.js"
      ],
      "exclude": [
        "dist",
        "node_modules"
      ]
    }
    c:\test\14558>type index.tsx
    import React from 'react';
    import Hello from './hello';
    
    class A extends React.Component<void, void> {
      render() {
        return (
          <div>
            <Hello>
              <div></div>
            </Hello>
          </div>
        );
      }
    }
    c:\test\14558>type hello.js
    // @ts-check
    
    import React from 'react';
    
    export default class Hello extends React.Component {
      render() {
        return <div>Hello</div>;
      }
    }
    
    c:\test\14558>tsc --v
    Version 2.3.2
    
    c:\test\14558>tsc --p tsconfig.json
    
    c:\test\14558>echo %ERRORLEVEL%
    0
  6. robin-anil commented on May 5, 2017

    @robin-anil

    does it work if you rename hello.js to hello.jsx ?

  7. mhegazy commented on May 5, 2017

    @mhegazy
    Contributor
    c:\test\14558>move hello.js hello.jsx
            1 file(s) moved.
    
    c:\test\14558>
    tsc
    
    c:\test\14558>echo %ERRORLEVEL%
    0
  8. gagarski commented on Jul 11, 2017

    @gagarski

    Mohamed Hegazy (@mhegazy)

    Did you try adding properties to Hello?
    It seems like Typescript infers that properties of Hello are of type {}. So you cannot render it from TypeScript as <Hello baz="world"/>.

    Here is the compiler output:

    error TS2339: Property 'baz' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Hello> & Readonly<{ children?: ReactNode; }> & Readonly<{}>'
    

    It can be worked around with React.createElement:

    React.createElement(Hello, {baz: "world"} as any)

    or by creating temporary variable with properties but this is quite ugly workaround. Can this be done better?

  9. gagarski commented on Jul 11, 2017

    @gagarski

    https://github.com/gagarski/tsx-jsx - complete minimalistic example

  10. artemyarulin commented on Aug 4, 2017

    @artemyarulin

    Can we please reopen it? It doesn't work if component have any props inside and it's a show stopper for React projects which are migrating to TypeScript

  11. 17 remaining items

  12. vkrol commented on Nov 22, 2017

    @vkrol

    Mohamed Hegazy (@mhegazy) this fix does not work if noImplicitAny compiler flag is enabled :(

  13. mhegazy commented on Nov 22, 2017

    @mhegazy
    Contributor

    Well.. it is an implicit any... if you want the strict no-anys-implicitly-added-by-the-compiler, then use `/** Augments */ to specify the type.

  14. vkrol commented on Nov 22, 2017

    @vkrol

    Mohamed Hegazy (@mhegazy) so in noImplicitAny-mode /** @augments ... */ is the only solution and it will not be changed in the future?

  15. gpeal commented on Nov 22, 2017

    @gpeal

    Mohamed Hegazy (@mhegazy) This makes it very difficult to incrementally adopt TS in a large codebase because we have hundreds/thousands of JS components that will not be converted for the foreseeable future.

  16. mhegazy commented on Nov 22, 2017

    @mhegazy
    Contributor

    but it is an implicit any. you can opt-out of this using --noImplicitAny false

  17. mhegazy commented on Nov 22, 2017

    @mhegazy
    Contributor

    so i miss understood the Veniamin Krol (@vkrol)'s comment. I thought he meant getting an error under --noImpclitAny --checkJs which is expected.. but looking at the code again, it is disabled for --noImplcitAny, and that is a bug and should be fixed. apologies for the miss understanding.

  18. mhegazy commented on Nov 22, 2017

    @mhegazy
    Contributor

    #20232 should fix that.

  19. gerges-zz commented on Dec 1, 2017

    @gerges-zz

    Just ran into this as well, just so I'm understanding, with #20232 this fix should work for an incrementally converted codebase when using a non TS React component inside of a TSX component with noImplicitAny enabled

  20. vkrol commented on Dec 3, 2017

    @vkrol

    Mohamed Hegazy (@mhegazy) Wesley Wigham (@weswigham) it is works in the latest nightly build. Thanks!

  21. danantal commented on Jan 17, 2018

    @danantal

    I ran into this as well.. while using react-select with latest typings. Has this issue been fixed in TS 2.6.2?

  22. ssunday commented on Feb 6, 2018

    @ssunday

    Dan Antal (@danantal) Running into this as well. Not on TS 2.6.2, though. I would upgrade, but it's a massive jump for the codebase.

  23. devharf2310 commented on May 2, 2018

    @devharf2310

    This works for me:

    //this is tsx file
    
    import React, { Component } from "react";
    
    const SomeComponent = require('./SomeComponent.js');
    
    /* tslint:disable */
    const JsSomeComponent: any = SomeComponent; //todo delete me after refactoring to TS
    /* tslint:enable */
    
    class MyTSXComponent extends Component {
        public render() {
            return <JsSomeComponent/>;
        }
    }
    
  24. locked and limited conversation to collaborators on Jul 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptFixedA PR has been merged for this issue

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions