5

In my program, I have lots of files with enum definitions like this and some files which join enums together. The enums are string-enums, so the indexing is not part of the problem. When I join enums together I get the error "Cannot access 'Both' before initialization". There are also circular imports, since I am using the combined enum in the first file. I understand the error message, however I import the files containing the necessary enums before defining 'Both'. Is this a typescript bug or am I missing something? I am using typescript in a React environment, so maybe I am missing the right tsconfig lines.



// firstFile.ts

export enum One
{
    A,
    B,
}

export enum Two
{
    C = 2,
    D,
}


// secondFile.ts, throws error

import { One, Two } from './firstFile';

export const Both = 
{
    ...One,
    ...Two,
}

2
  • 1
    try import { One, Two } from './firstFile';, Problem might be in a way how you import 'firstFile', because you are using absolute import instead of relative Commented Dec 1, 2021 at 11:27
  • @captain-yossarian Yes, I mistyped this. It is not my actual code, only for demonstration Commented Dec 1, 2021 at 11:35

1 Answer 1

3

Circular dependencies are allowed in TypeScript (and ECMAScript as well), the static resolution of import and export clauses will work, but you have to be careful of the execution order of the files, depending on the entry point. Indeed, when a circular dependency is met, the entry point acts as the trunk of the dependency tree, so the other files execute before. When a file executes all of its top-level code executes, and will fail if it meets unresolved variables.

Now let's see what happens in your particular case. Your code transpiles to something like this:

firstFile.ts

import { Both } from "./secondFile.js";
export var One;
(function (One) {
    One[One["A"] = 0] = "A";
    One[One["B"] = 1] = "B";
})(One || (One = {}));
export var Two;
(function (Two) {
    Two[Two["C"] = 2] = "C";
    Two[Two["D"] = 3] = "D";
})(Two || (Two = {}));

secondFile.ts

import { One, Two } from './firstFile.js';
export const Both = Object.assign(Object.assign({}, One), Two);

If you use secondFile.ts as the entry point, firstFile.ts will execute first and will not throw any error because Both is unused in firstFile.ts.

However, if you add let's say a console.log(Both.A) at the end of firstFile.ts it will fail with a Cannot access 'Both' before initialization error because secondFile.ts has not executed yet, so Both is exported but not initialized.

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

3 Comments

I'll write this as a comment because it's my own opinion: circular dependencies increase the complexity of the code and makes the responsibility of each file unclear. I strongly suggest you to review your design in order to remove that circular dependency.
Thank you so much! I will look into refactoring my code to unwind the mess of imports.
In my case class B extended from class A and in class A I was using instance of B which caused the circular dependency

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.