1

I've set up a project with TypeScript, Webpack, Babel, and React, but i'm running into some trouble with using enum members as keys for an object.

The file in question looks like this:

// traits.ts
import { Trait } from "models/abilities";

const traits: { [key in TraitName]: Trait } = {
  [TraitName.Combat]: new Trait({
    aspect: Aspect.Power,
    name: TraitName.Combat
    }),
    ...
}

The object TraitName is an enum created in a global .d.ts file:

/// global.d.ts

enum TraitName {
  Combat = "Combat",
  ...
}

This all works fine for the build. It all compiles successfully in Webpack and TypeScript doesn't complain. However, when I load up my browser, I get this error: "Reference Error: TraitName is not defined"

Checking the code in the dev console, it appears everything transpiled fine except the enum. It is still represented as if it is an object in the file/imported into the file, but it isn't being imported.

__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var models_abilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! models/abilities */ "./src/models/abilities/index.ts");

const traits = {
  /* It starts complaining here */ [TraitName.Combat]: new models_abilities__WEBPACK_IMPORTED_MODULE_0__.Trait({
    aspect: Aspect.Power,
    name: TraitName.Combat,
    ...

Should those enum references not be replaced with their values during transpilation? I don't know if maybe I have something configured wrong, but I'd appreciate some insight.

TS Config:

{
  "compilerOptions": {
    "target": "es6",
    "outDir": "./build",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "baseUrl": ".",
    "paths": {
      "data/*": [
        "src/data/*"
      ],
      "models/*": [
        "src/models/*"
      ],
      "presentation/*": [
        "src/presentation/*"
      ],
      "services/*": [
        "src/services/*"
      ],
      "utils": [
        "src/utils"
      ]
    }
  },
  "include": [
    "src"
  ]
}

Webpack Config:

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = {
  entry: path.join(__dirname, "src", "index.tsx"),
  output: {
    path: path.join(__dirname, "build"),
    filename: "[name].[contenthash].bundle.js"
  },
  mode: process.env.NODE_ENV || "development",
  resolve: {
    extensions: [".ts", ".tsx", ".js", ".jsx"],
    plugins: [new TsconfigPathsPlugin({ extensions: [".ts", ".tsx", ".js", ".jsx"] })]
  },
  devServer: {
    port: 3000,
    liveReload: false,
    hot: true
  },
  module: {
    rules: [
      {
        test: /\.js(x)?$/,
        exclude: /node_modules|__tests__/,
        use: ["babel-loader"]
      },
      {
        test: /\.ts(x)?$/,
        exclude: /node_modules|__tests__/,
        use: ["babel-loader"]
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: ["style-loader", "css-loader"]
      }
    ],
  },
  stats: {
    assets: false,
    builtAt: false,
    moduleAssets: false,
    cachedModules: false,
    runtimeModules: false,
    cachedAssets: false,
    children: false,
    chunks: false,
    context: path.resolve(__dirname, "src"),
    errors: true,
    hash: false,
    logging: "warn",
    modules: false,
    timings: false,
    version: false,
    warnings: true
  },
  plugins: [
    new ESLintPlugin({
      context: "./src",
      extensions: ["ts", "tsx"]
    }),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, "src", "index.html"),
    }),
  ],
};

.babelrc

{
  "presets": [
      "@babel/env",
      "@babel/react",
      "@babel/preset-typescript"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

NOTE: I was loading typescript with ts-loader, but that produced the same result and I'm seeing documentation that simply uses babel to load it. Not really sure which I should be doing, but changing that doesn't fix this problem.

1
  • Babel's documentation on @babel/preset-typescript does mention special handling for enums, but I agree with @ghybs's answer -- probably just the .d.ts extension. Commented Jul 30, 2022 at 6:13

1 Answer 1

2

Files with .d.ts extension are not transpiled.

In your case, you could probably just rename it with .ts extension.

Sign up to request clarification or add additional context in comments.

2 Comments

So there is no way to globally declare enums? they must always be imported?
Okay, so digging in, I did find that changing it to a .ts file can still allow it to be considered global, but "isolatedModules" needs to be turned off and I have to use the typescript compiler to build it instead of anything through webpack. I'm running into other issues now, but they are unrelated to this one - need to figur eout paths for webpack seperate from typescript paths. So, thanks for the help and pointing me in the right direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.