What is the process for enabling Namespaces in CRA?

When creating a TypeScript React app, I used the following command:

yarn create react-app my-app --template typescript

This setup compiles my project using Babel and bundles it with webpack. Now, I want to utilize TypeScript namespaces, which are not natively supported in Babel. However, they can be enabled by installing certain packages:

I made adjustments in the package.json file, changing react-scripts start to react-app-rewired start.

Additionally, I created a custom configuration file named config-overrides.js:

const {
    override,
    addExternalBabelPlugin
  } = require("customize-cra");

module.exports = override(
    addExternalBabelPlugin([
        "@babel/plugin-transform-typescript",
        { allowNamespaces: true }
    ])
);

Despite these steps, compiling the project still results in a syntax error, indicating that the plugin for non-declarative namespaces was not properly enabled:

SyntaxError: /home/m93a/my-app/script.ts: Namespace not marked type-only declare. Non-declarative namespaces are only supported experimentally in Babel. To enable and review caveats see: https://babeljs.io/docs/en/babel-plugin-transform-typescript

What is the correct setup process to ensure that even non-declarative namespaces compile successfully in the project?


EDIT: The root cause of the issue with my project turned out to be different than expected. Refer to my own answer below for more insights.

Answer №1

To achieve the desired result, it is recommended to utilize the addBabelPlugin method instead of addExternalBabelPlugin.

A Simplified Explanation

Upon reviewing the documentation, we find:

addExternalBabelPlugin(plugin)

The webpack configuration in create-react-app consists of two rules for the babel-loader: one for code within the src/ directory by default, and another for external code (e.g., from node_modules). Plugins can be added to the external loader using addExternalBabelPlugin, mirroring the usage of addBabelPlugin.

Further inspection of the

react-scripts/config/webpack.config.js
reveals these two entries for babel-loader:

  1. Located at webpack.config.js#L396 is the babel-loader for include: paths.appSrc and for \.(js|mjs|jsx|ts|tsx)$/ which addBabelPlugin incorporates plugins for, accompanied by this comment:

    // Process application JS with Babel.
    // The preset includes JSX, Flow, TypeScript, and some ESnext features.
    
  2. Found at webpack.config.js#L452 is the babel-loader for /\.(js|mjs)$/ which addExternalBabelPlugin adds plugins for, remarked by:

    // Process any JS outside of the app with Babel.
    // Unlike the application JS, we only compile the standard ES features.
    

In order for

@babel/plugin-transform-typescript
to affect the initial babel-loader pertaining to the application's src folder, addBabelPlugin must be utilized for that specific babel-loader setup.

Lastly, ensure your package.json scripts are updated to run via react-app-rewired:

"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"

You can explore a straightforward CRA Typescript project showcasing the use of a class within a namespace here: https://github.com/clytras/cra-ts-namespaces

Answer №2

Utilize rescripts for customizing Babel configuration To achieve this, you can implement the following steps:

  1. Begin by creating a new application using
    create-react-app my-app --template=typescript
    , or work with an existing one
  2. Proceed to install rescripts by running npm i -D @rescripts/cli
  3. In your package.json file, substitute react-scripts with rescripts as outlined in the rescripts documentation
  4. Install the rescript plugin for configuring babel:
    @rescripts/rescript-use-babel-config
  5. Include the provided snippet in your package.json file
"rescripts": [
    [
        "use-babel-config",
            {
                "presets": [
                    "react-app",
                    [
                        "@babel/preset-typescript",
                        {
                            "allowNamespaces": true
                        }
                    ]
                ]
            }
        ]
    ]

The rescripts tool leverages a plugin to expand the babel configuration. By extending the default react-app babel setup, we ensure compatibility while modifying the installed preset to include the allowNamespaces parameter.

Answer №3

During my troubleshooting process, I encountered a unique issue that persisted even after implementing suggestions from others. The root cause of the problem was identified as a bug in Babel that hinders the merging of enum and namespace. Here is an example snippet that would not function correctly:

export enum Bar
{
    x, y, z
}

export namespace Bar
{
  export function baz()
  {
    return "baz"
  }
}

Interestingly, Babel displays a misleading error message when confronted with this code:

SyntaxError: script.ts: Namespace not marked type-only declare. Non-declarative namespaces are only supported experimentally in Babel. To enable and review caveats see: https://babeljs.io/docs/en/babel-plugin-transform-typescript

I have logged an official complaint regarding this issue, in hopes of prompt resolution or improved error messaging. Meanwhile, a temporary solution can be implemented:

export enum Bar_
{
    x, y, z
}

export type Bar = Bar_

export namespace Bar
{
  export const x = Bar_.x
  export const y = Bar_.y
  export const z = Bar_.z
  export function baz()
  {
    return "baz"
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to locate 'reflect-metadata' module within Docker container on Production Server

I encountered an error: module.js:550 throw err; ^ Error: Cannot find module 'reflect-metadata' at Function.Module._resolveFilename (module.js:548:15) at Function.Module._load (module.js:475:25) at Module.require ( ...

Leveraging vuex in conjunction with typescript allows for efficient management of state in namespace modules,

I am currently integrating vuex with typescript and namespaces module in my project. Within this setup, I have two distinct modules: "UserProfile" and "Trips". So far, everything is functioning smoothly within the confines of each module. However, I have ...

Implementing Routes in Express Using Typescript Classes

Seeking assistance in converting a Node.js project that utilizes Express.js. The objective is to achieve something similar to the setup in the App.ts file. In pure Javascript, the solution remains unchanged, except that instead of a class, it involves a mo ...

Error TS7053 occurs when an element is given an 'any' type because a 'string' expression is being used to index an 'Object' type

When attempting to post data directly using templateDrivenForm and retrieve data from Firebase, I encountered the following type error message. Here are the relevant parts of my code: // Posting data directly using submitButton from templateDrivenForm onC ...

Issue: Unable to import certain modules when using the Typescript starter in ScreepsTroubleshooting: encountering

Having trouble with modules in the standard typescript starter when transferring to screeps. One issue is with the following code: import * as faker from 'faker'; export function creepNamer() { let randomName = faker.name.findName(); return ...

The selectors in NgRx store are failing to retrieve data from the main global store

As I delve into the world of ngrx, I find myself struggling to fully understand and implement it effectively within my application. Recently, I integrated ngrx version 8.3 into my project in hopes of organizing my state management efficiently. My goal is ...

React Router Issue: Component Not Rendering When <nav> Element Is Incomplete

I am currently experiencing an issue with rendering a component in my React TypeScript application using React Router. The problem arises when trying to navigate to the AddTask component by clicking on a link within a <nav> element. Strangely, the co ...

Discover the unseen: The ultimate guide to detecting visible objects in a (deferLoad) event

I'm utilizing the (deferLoad) method to load an image gallery in a more controlled manner. Is there any event available that can inform me about which items are currently visible? The main goal is to load a set of data along with an image path, and t ...

ReactJS: error occurs when trying to fetch data and encountering issues with reading properties

I am currently attempting to initiate an API call (a GET request) in order to download a document. However, I am encountering an error when making the API call: TypeError: Cannot read properties of undefined (reading 'payload') const printPin ...

Stop receiving updates from an Observable generated by the of method

After I finish creating an observable, I make sure to unsubscribe from it immediately. const data$ = this.httpClient.get('https://jsonplaceholder.typicode.com/todos/1').subscribe(res => { console.log('live', res); data$.unsubscr ...

"Using RxJS to create an observable that filters and splits a string using

I need to break down a string using commas as separators into an observable for an autocomplete feature. The string looks something like this: nom_commune = Ambarès,ambares,Ambares,ambarès My goal is to extract the first value from the string: Ambarès ...

NextJS applications can encounter issues with Jest's inability to parse SVG images

Upon running yarn test, an unexpected token error is encountered: Jest encountered an unexpected token This typically indicates that Jest is unable to parse the file being imported, suggesting it's not standard JavaScript. By default, Jest will use ...

Issues with TypeScript "Compile on save" functionality in Visual Studio 2015

The feature of "Compile on save" is not functioning properly for me since I upgraded to Visual Studio 2015. Even though the status bar at the bottom of the IDE shows Output(s) generated successfully after I make changes to a .ts file and save it, the resul ...

A TypeScript default function that is nested within an interface

This is functioning correctly interface test{ imp():number; } However, attempting to implement a function within the interface may pose some challenges. interface test{ imp():number{ // do something if it is not overwritten } } I am ...

Is there a way to verify if a user taps outside a component in react-native?

I have implemented a custom select feature, but I am facing an issue with closing it when clicking outside the select or options. The "button" is essentially a TouchableOpacity, and upon clicking on it, the list of options appears. Currently, I can only cl ...

Troubleshooting a TypeScript error when trying to access an imported service in Angular 2

I've been working on creating a form that allows users to input required details, which will trigger a server call and save the information. However, no matter what I try, I keep encountering the following error: ORIGINAL EXCEPTION: TypeError: this.po ...

React array fails to update upon modification

Hey there! I've created a component that takes an array of strings, combines them, and then renders a typing animation by wrapping each character in a span tag with toggling opacity from 0 to 1. I noticed an issue when switching the order of displaye ...

Tips for showing data from an hour ago in Angular

Here is the code snippet provided: data = [ { 'name' : 'sample' 'date' : '2020-02-18 13:50:01' }, { 'name' : 'sample' 'date' : '2020-02- ...

Simultaneously accessing multiple APIs

I am currently facing an issue with calling two API requests sequentially, which is causing unnecessary delays. Can someone please advise me on how to call both APIs simultaneously in order to save time? this.data = await this.processService.workflowAPI1(& ...

What is the reason behind installing both Typescript and Javascript in Next.js?

After executing the command npx create-next-app --typescript --example with-tailwindcss my_project, my project ends up having this appearance: https://i.stack.imgur.com/yXEFK.png Is there a way to set up Next.js with Typescript and Tailwind CSS without i ...