Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript error TS2449: Class 'x' used before its declaration

Tags:

typescript

I don't understand the tsc compilation process with respect to<reference> and splitting the classes of a namespace across multiple files. I'm using the pattern:

src/base.ts

namespace MyNameSpace {
  export class Base {
     /** constructor, etc. */
  }
}

src/subclass.ts

/// <reference path="./base.ts" />

namespace MyNameSpace {
  export class Subclass {
     /** constructor, etc. */
  }
}

This trivial example works. But as I use the pattern on more files, I periodically get the error TypeScript error TS2449: Class 'x' used before its declaration..

Are we back to manually managing declaration orderings, like .c/.h files? If so, what tools will help be back track the reference to find the error?

My aim to have a manageable set of files that compile into a single .js and .d.ts (for another TypeScript library to use). If there a better solution for this scenario? Attempts with variations of Webpack and imports have failed me.

If it matters, I'm also using nested namespaces, where the members are defined in subdirectories. I'm always using relative reference paths.

This is very similar to typescript Base type 'xxxx' is referenced before its declaration, which dealt with a module split across multiple files.

like image 686
Anm Avatar asked Dec 06 '17 17:12

Anm


3 Answers

Major Terminology Alert

Namespaces are not preferred over modules. This is a very important point. Let's dive into the history...

Namespaces used to be declared like this:

module MyNamespace {

}

But they are now declared like this:

namespace MyNamespace {

}

When declaring a namespace, the namespace keyword is preferred to the old module keyword.

The reason the module keyword was replaced with namespace is that people confused them with "modules". You can see where the confusion might come from! Now actual modules (i.e. files that export or import something) are actually a bit better than namespaces, which is why I have spent the entire answer so far covering all this.

Use Modules

With this in mind, you might consider using modules. Each module gives you a naming context and keeps stuff out of the global scope. You can import and export and everything should work as expected (and you can still bundle it if you like).

src/base.ts

export class Base {

}

src/subclass.ts

import * as Example from './subclass.ts';

export class Base extends Example.Base {

}

Namespace Merging

If you want to stick with namespaces, you have to respect that everything you place within a namespace (even when that namespace is spread across multiple files) contributes to a single naming context... so you'll have to name the subclass differently.

src/base.ts

namespace MyNameSpace {
  export class Base {
     /** constructor, etc. */
  }
}

src/subclass.ts

/// <reference path="./base.ts" />

namespace MyNameSpace {
  export class Sub extends Base {
     /** constructor, etc. */
  }
}

So ultimately, you can choose modules (proper external modules) where each file has its own naming context, and you can easily avoid naming collisions - or namsepaces where you'll need to be aware that each namespace is a single naming context.

Small Print

In may examples I have inherited Base in the subclass for illustration. You're question didn't exactly do that, but I wanted to illustrate the concept. The question had two classes within the namespace with the same name, which is a duplicate name conflict.

like image 180
Fenton Avatar answered Nov 16 '22 20:11

Fenton


I was able to resolve this error by restarting Visual Studio as mentioned in the comments by @Quentin2

like image 38
Jonas Äppelgran Avatar answered Nov 16 '22 20:11

Jonas Äppelgran


typescript some time work find, some time not, and this error come again.

//file B.ts
class B {}

//file A.ts
class A extends B{}
error TS2449: Class 'B' used before its declaration.

If I change file A.ts to B.ts, A.ts to B.ts, then the problem fixed, haha!

I think it is because A is smaller than B, at ascii, the typescript compiler check them by file name. It is so freak! It's not smart enough :(

Or we must use module....

like image 2
govo Avatar answered Nov 16 '22 18:11

govo