0

my company's working way is quite weird. We use a PHP template engine to copy all of file into a single HTML and serve it. It goes as follow:

Main html

<script>
    (() => {
        const foo = 'bar';
        {{ include('xxx.js') }}
    })
    {{ include('zzz.js') }}
</script>

xxx.ts

declare const foo: string;
(() => {
    console.log(foo);
})()

As you can see, there are 2 layers of IIFE, one in the main HTML and another one in each .ts to ensure the scope of variable is contained correctly in each .ts file. I then compile xxx.ts into xxx.js using tsc.

The problem is that now I have an additional file yyy.ts that I want to include right below xxx.ts in the main.html's IIFE. Lets assume yyy.ts is exactly the same with xxx.ts.

yyy.ts

declare const foo: string;
(() => {
    console.log(foo);
})()

Here I run into an issue at foo in both file. The error is Cannot redeclare block-scoped variable.

I can't put the foo into a global.d.ts file cause it's not global since it's only valid to xxx.js and yyy.js

I have done some reading and see that the way TS compile is that if the file doesn't have import/export, it will treat all of the variable as global variable.

How can I solve this issue? 2 ways that I can kind of think of are:

  • Find a way to set up tsconfig to treat each file as separated file. I haven't found a good solution to this
  • In .ts file, declare the global variable inside the IIFE. But I ran into error Modifiers cannot appear here.

Any helps are appreciated. Thanks!

9
  • is there a specific reason why the declarations needs to have the same name? Commented May 20, 2021 at 14:35
  • Maybe get your PHP script to create the IIFE Commented May 20, 2021 at 14:36
  • @SeppeMariën some of my variables is actually global, but just with some files, and not others. However, the problem is that TS is treating all of my files as connected. So the more declaration I made, the more polluted the global scope will be Commented May 20, 2021 at 14:40
  • @Keith the issue is not with the compiled scope, so the IIFE is fine regardless of how I generate it. The problem is with TS treating all of my files as connected, meaning all the declared variable are connected too Commented May 20, 2021 at 14:41
  • Yes but this is normal behavior. It is not even typescript doing this it is Javascript. Typescript is only warning you. The only way as far as I know you need to import your files like: <script type="module" src="xxx.js"></script> but like you said it is the php that does the include of the file Commented May 20, 2021 at 14:47

1 Answer 1

1

I've a feeling you didn't understand my point about the IIFE been done in PHP and not TS. So I thought it might make sense if I show some example.

From what I can gather say you have a global var called foo, and you want that to be included in xxx & zzz..

First, don't put the IIFE inside the TS files. Otherwise like you have found out your going to get Cannot redeclare block-scoped variable

So below is an idea that I believe will do what your after.

File xxx.TS

declare const foo: string;

const msg = "hello";
console.log(`${msg) ${foo)`);

File zzz.TS

declare const foo: string;

const msg = "goodbye";
console.log(`${msg) ${foo)`);

Now if inside our PHP file we did ->

<script>
    (() => {
      const foo = 'bar';
      (() => { {{ include('xxx.js') }} })
      (() => { {{ include('yyy.js') }} })
    })
</script>

So in the above, firstly you have a global var foo, but only global for your TS files, each TS files can also have it's own local vars. In above you can see I've defined a local var msg that has hello & goodbye different in each TS file.

So if you run the above you should then see something like ->

hello bar
goodbye bar

And none of the above is going to pollute your windows global.

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

3 Comments

The problem is that tsc will read this declare const foo: string; in both xxx and zzz and considered them duplication and throw Cannot redeclare block-scoped variable error. The reason is that tsc consider every file that doesn't have import/export to be a global file, and anything declare in them is global. So in your case, if in zzz.ts, I refer to foo, tsc is still okay with it. It's not about compiled js cause I know that it's correct js, but about tsc understanding the scope of the variable incorrectly
@TreeNguyen I though you was compiling these separately. IOW: tsc xxx.ts & tsc yyy.ts, and not just tsc.. If you want to use tsc on it's own you will want to place xxx & yyy in it's own directory with it's own tsconfig.json, and use the include option. The advantage of this approach it also make Editors happy. Doing tsc on it's own with a single tsconfig will treat all the files as 1 project, and that's why you get the Cannot redeclare block-scoped variable
You could also create multiple tsconfig files, and use the --project option, but the individual directories I believe is the easier option. You could also use the import / export inside each directory, to kind of create a custom bundling system, each directory could compile to a single file, but you still have xxx and yyy as one file each.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.