TypeScript 2.8: preact and react in one compilation

1.5k Views Asked by At

According to below site, I thought I can use preact and react both in one compilation. But when I'm trying to use these libraries together in one compilation there is a conflict. I think preact and react still has global JSX namespace, so cannot be mixed for now. If my configuration is wrong please let me know.

https://blogs.msdn.microsoft.com/typescript/2018/03/27/announcing-typescript-2-8/#jsx-namespace-resolution

JSX is resolved via the JSX Factory Currently, when TypeScript uses JSX, it looks up a global JSX namespace to look up certain types (e.g. “what’s the type of a JSX component?”). In TypeScript 2.8, the compiler will try to look up the JSX namespace based on the location of your JSX factory. For example, if your JSX factory is React.createElement, TypeScript will try to first resolve React.JSX, and then resolve JSX from within the current scope.

This can be helpful when mixing and matching different libraries (e.g. React and Preact) or different versions of a specific library (e.g. React 14 and React 16), as placing the JSX namespace in the global scope can cause issues.

Here is my test project

  • OS: windows 10 64
  • node: 6.9.5
  • npm: 3.10.10
  • tsc: 2.8.3
  • webpack: 4.6.0
  • webpack-cli: 2.0.15

directory structure

  • dist
  • src
    • components
      • PreactUser.tsx
      • ReactUser.tsx
    • index.tsx
  • index.html
  • package.json
  • tsconfig.json
  • webpack.config.json

src/components/PreactUser.tsx (first line: /** @jsx h */)

import {h, Component} from 'preact';

export interface HelloWorldProps {
    name: string
}

export default class PreactUserComp extends Component<HelloWorldProps, any> 
{
    render (props: HelloWorldProps) {
        return <h1>Hello {props.name}!</h1>
    }
}

Originally the first line is /** @jsx h */. But this editor cannot recognize it as a correct code.

src/components/ReactUser.tsx (first line: /** @jsx React.createElement */)

import * as React from "react";

export interface HelloProps { firstName: string; lastName: string; }

interface Person {
    firstName: string;
    lastName: string;
}
class User implements Person {
    firstName: string;
    lastName: string;
    constructor(firstName: string, lastName: string) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
function formatName(user:User): string {
    return user.firstName + ' ' + user.lastName;
}

export class ReactUserComp extends React.Component<HelloProps, {}> {
    render() {
        return <h1>Hello {this.props.firstName} {this.props.lastName}!</h1>;
    }
}

src/index.tsx (first line: /** @jsx h */)

import { h, render } from 'preact';
import PreactUserComp from './components/PreactUser';

render(<PreactUserComp name="Preact" />, document.querySelector('#app'));

package.json

{
    "name": "typescript-preact-react",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
        "@types/react": "^16.3.13",
        "@types/react-dom": "^16.0.5",
        "react": "^16.3.2",
        "react-dom": "^16.3.2",
        "preact": "^8.2.7",
        "ts-loader": "^4.2.0",
        "typescript": "^2.8.3",
        "webpack": "^4.6.0"
    },
    "devDependencies": {
        "typescript": "^2.8.3",
        "webpack": "^4.6.0",
        "webpack-cli": "^2.0.15"
    }
}

tsconfig.json

{
    "compilerOptions": {
        "sourceMap": true,
        "module": "commonjs",
        "jsx": "react",
        "target": "es5"
    },
    "include": [
        "src/*.ts",
        "src/*.tsx"
    ]
}

webpack.config.js

var path = require('path');

module.exports = {
    devtool: 'source-map',
    entry: './src/index.tsx',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'app.js'
    },
    resolve: {
        extensions: ['.ts', '.tsx']
    },
    module: {
        rules: [
        {
            test: /\.tsx?$/,
            exclude: /node_modules/,
            loaders: ['ts-loader']
        }
        ]
    }
}

index.html

<div id="app"></div>
<script src="dist/app.js"></script>

Originally index.html has few more codes, however this editor cannot recognize it as a correct code, so I summarize the code.

1

There are 1 best solutions below

0
Mithunish Prabhakaran On

This is indeed the problem. In order to use React along with Preact using typescript you need to have your own declaration files(typings.d.ts).

I don't exactly know the details of how it should be done. But I wanted a similar setup for my project and found a Github project that tries to solve this problem.

link: Hotell/react-preact-typescript-interop

I haven't tried it yet. But I think this would help you to some extent.