TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Add compiler option to allow module types to be checked in non module output files

Open KeithHenry opened this issue 3 years ago • 22 comments

Search Terms: import type, export {}

Suggestion

In #41513 and #41562 projects are broken by a design change to always include export {}; in the JS output if import or import type is in the TS source, regardless of whether it is in the JS output. This is a breaking change for a lot of developers and painful to fix (and by fix I mean practically get the output of our TS project to run in browsers, not necessarily adhere to ECMA spec compliance and best possible practice).

However, export {}; considered desirable:

You're free to suggest a new compiler option but this is the intentional behavior. Originally posted by @RyanCavanaugh in https://github.com/microsoft/TypeScript/issues/41513#issuecomment-727057724

Please could we have a new compiler option to not force all files that in any way use ES modules to always have to include export {}; in the JS output.

I'm not sure of the best way for this to be applied, but the goal would be

  • Type checking compatible with an ESM project.
  • Output compatible with the current state of module support in browsers.

This could be:

  • A compiler option that causes import type to not implicitly convert output to a module, (my preference because it still avoids any output JS having import without export, which caused #38696) or
  • A compiler option to not add export {}; to all modules, or
  • A //@directive we add to a file to express our intent to not output a module, or
  • A new reference type ... TS-only syntax to signal that we want to use the definition but not output a module

Whatever is easiest to code and causes least friction/confusion for the community.

Use Cases

I have a large TS project that uses numerous web workers, a service worker and web components that load side effects.

In the first two cases including export {}; breaks the resulting JS, as these workers are not modules and are not intended to produce module loaded JS output.

In the case of side effect web components no export is expected (they use customElements.define) so it's just wasted bytes, but it doesn't break anything. Across a project with a lot of components the many export {}; that will never be referenced by anything adds up.

In addition during migration between different reference types it may be extremely beneficial to not strictly enforce adherence to one type or the other, at least while not in production. Any modules = all must be modules effectively makes this migration harder, even if it is a sound best practice.

Examples

I have a model MyModel.d.ts.

In worker.ts I want TS to check my code against this model:

import type MyModel from './MyModel';
const test: MyModel = {};
test.propertyInModel = 1; // works and has intellisense
// test.propertyNotInModel = 1; throws compile error!

I want to use the JS output this with a worker in another file:

const worker = new Worker('path/worker.js');

This worked in 3.8, but fails in 4.0 due to #41562

Checklist

My suggestion meets these guidelines:

  • [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code (it would fix a lot of projects broken by 4.0)
  • [x] This wouldn't change the runtime behaviour of existing JavaScript code (it would be opt-in)
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.) (we're removing additional content that wasn't in 3.8)
  • [x] This feature would agree with the rest of TypeScript's Design Goals. (particularly 4, 7 and 11)

KeithHenry avatar Nov 17 '20 17:11 KeithHenry

A new reference type ... TS-only syntax to signal that we want to use the definition but not output a module

This exists:

- import type MyModel from './MyModel';
+ type MyModel = import('./MyModel').default;
const test: MyModel = {};
test.propertyInModel = 1; // works and has intellisense
// test.propertyNotInModel = 1; throws compile error!

There are a couple problems here. The first is a misconception about the purpose of import type, which is not necessarily represented in this issue, but I’ve seen it in related issues so I want to remove it from any present confusion. The motivation behind import type never had anything to do with keeping scripts scripty. It makes your source file a module, just like a regular import of a type/interface that also gets elided. I’ve seen a lot of people react to this news with comments like “Wait, so why would I ever use that then‽” which is the correct response. A select few groups of users had good reasons to want import type; they are not useful to most people. Given that they behave exactly like import SomeInterface from "./whatever", we can completely ignore type-only imports in this discussion.

So the question becomes, how do I reference types from a module in a script? And the answer is, and has always been, the import('...') type syntax. That didn’t change with import type. You might say in response, “I don’t like using that syntax; it’s verbose and unwieldy and I am left choosing between the two bad options of (1) repeating the import(...) syntax everywhere I need it and (2) writing a type alias (as in the above example) that becomes globally visible, due to the file’s scripty nature.” That’s a reasonable argument outlining a problem that I think is well worth solving. You might also say “Look, what I want is very simple; it literally used to work this way before #38712; just give me some way to write imports in a file that I know will be elided without putting export {} in my JS, and everything will work fine.” I want to explore the problems with this argument, because it does sound reasonable at first glance.

The problem is determining the scope of top-level declarations in the file. Suppose we had a directive like // @ts-really-not-a-module that would enforce that all imports can be safely elided and no exports are written, and would direct the transformer not to add export {}, guaranteeing that the JS emit would be script-friendly. This would be easy to implement and would totally satisfy your request. The problem is that the scope of that file’s declarations is really unclear. In your case, you’re loading it into a web worker, which has its own scope, so using the same scope rules that we use for modules makes sense. However, someone could just as well load that JS into a <script src="...">, where its top-level scope is shared with other scripts. In this case, we would fail both in letting you legitimately share top-level variables across scripts as well as in issuing duplicate declaration errors when you accidentally introduce the same name twice across different scripts that share the same scope. More pragmatically, there is a lot of compiler code that assumes that any import/export declaration does in fact make that file a module, so I suspect any feature that would let files import types but be treated like scripts would be a difficult change.

This is why I’m skeptical of a directive or compiler option that would “simply” let you use imports in a file but emit a script. Maybe there’s something we could do for Web Workers specifically. But I would like to understand how bad of a solution the import('...') type syntax really is.

andrewbranch avatar Nov 17 '20 21:11 andrewbranch

@andrewbranch Cheers, that's a good workaround for #41562 and I've closed it.

As an alternate syntax workaround that works, thanks for letting me know I can import types like that, though I still think it's somewhat confusing and that there is a valid use case for a compiler option/directive.

In your case, you’re loading it into a web worker, which has its own scope, so using the same scope rules that we use for modules makes sense. However, someone could just as well load that JS into a <script src="...">, where its top-level scope is shared with other scripts.

Who would do that? I'm not writing an API or public library. I think this directive would be a very bad idea in the situation you describe, but this is a web worker - it's going to fail if you load it with <script src="..."> anyway because it was written as a background worker and is doing things that aren't available to window.

This wouldn't be for common practice, this would be so that in the corner case where we knew the output JS would be loaded in a certain way we could ensure that TS knows not to break that. Think like @ts-ignore - I shouldn't use it, but practically sometimes it's really useful, even if only during development.

The problem isn't that TS forces export {}; most of the time, the problem is that there is no way to not emit export {}; in any cases (no matter how narrow) where it isn't wanted.

In this case, we would fail both in letting you legitimately share top-level variables across scripts as well as in issuing duplicate declaration errors when you accidentally introduce the same name twice across different scripts that share the same scope.

It's top level scope can't be shared with other scripts, in a worker it's a whole new entry point (from the point of view of bundlers).

Take the case where we can use const worker = new Worker('path/worker.js', { type: 'module'}) - that worker.js won't have duplicate declaration errors, quite the opposite: anything we want to use in the worker we need to declare again. It needs its own code splitting (incidentally this is something bundlers are often bad at).

A very common practice with web workers is passing data back and forth - the main JS passes an entity across using postMessage and the web worker does something time consuming with it asynchronously. This means the workers tend to be very focused (i.e. typically don't want to import all the code used by the main library) but do need to reference the same record/interface type definitions a great deal.

Suppose we had a directive like // @ts-really-not-a-module

Thinking on this... far more useful (in the specific context of workers) would be a // @ts-context-worker that also changed the definition of self (and avoided common kludges like const worker = self as unknown as Worker;). That's probably a much bigger overall issue though.

KeithHenry avatar Nov 18 '20 10:11 KeithHenry

Who would do that? I'm not writing an API or public library. I think this directive would be a very bad idea in the situation you describe, but this is a web worker - it's going to fail if you load it with <script src="..."> anyway because it was written as a background worker and is doing things that aren't available to window.

My point is that there is literally nowhere you’re telling TypeScript that this file is exclusively targeted for a web worker. (In fact, if you’re getting export {} in it, that means it is part of a program where your tsconfig says, implicitly or explicitly, that it is targeting an es2015+ module system, which is not true for that file. You could definitely look at this whole problem as a configuration error—you are compiling this file with incorrect settings. That said, it’s kind of tedious to split into its own program, and would still emit module code with any of the existing module or target settings.) The built-in assumption is that non-module code (scripts) do share global scope, because you’re going to load them with script tags, because when TypeScript was invented, both bundlers and Web Workers were in their infancy, and that’s literally how people got JavaScript onto their sites. So while we have already established that certain things would coincidentally solve your problem because you are using web workers, I’m explaining that they cannot be generalized to all non-module code.

Think like @ts-ignore - I shouldn't use it, but practically sometimes it's really useful, even if only during development.

We resisted introducing // @ts-ignore for a long time! I’m glad it exists, but it’s not exactly an ideological blueprint for new features. We’re interested in actually solving these problems, not just silencing them.

It's top level scope can't be shared with other scripts, in a worker it's a whole new entry point (from the point of view of bundlers).

Again, TypeScript does not know anything about your workers or bundlers—people do still use scripts with shared global scope.

Thinking on this... far more useful (in the specific context of workers) would be a // @ts-context-worker that also changed the definition of self (and avoided common kludges like const worker = self as unknown as Worker;). That's probably a much bigger overall issue though.

This is already what you would get if you compiled your web worker files with a tsconfig that had "lib": ["webworker"] instead of "lib": ["dom"]. But, this has no effect on the module system.

andrewbranch avatar Nov 18 '20 17:11 andrewbranch

@andrewbranch I think this might be how we're using TS, which could be completely wrong...

... your tsconfig says, implicitly or explicitly, that it is targeting an es2015+ module system ... ... This is already what you would get if you compiled your web worker files with a tsconfig that had "lib": ["webworker"] instead of "lib": ["dom"].

This is fine if my entire project is exclusively DOM (with ES module import) or my entire project is exclusively workers (with importScripts). If it isn't I need multiple tsconfig.json files and rules for where to apply them.

In practice I'm using workers as kind of background threads - something is slow in the UI and causes jank/dropped frames, so I split it out into a worker and call it with Comlink (or something similar). In a large web application I have many files that need to be treated as web workers, arranged near the code that calls them and that they work closely with.

So this leads to lots and lots of tsconfig.json files and me spending more time messing about with config than actually writing code.

TypeScript does not know anything about your workers or bundlers

Exactly! It doesn't know so it assumes. Now that assumption may be best practice and it may be the right call 99% of the time, but there's no way to opt out of it in the times when it isn't.

We resisted introducing // @ts-ignore for a long time! I’m glad it exists, but it’s not exactly an ideological blueprint for new features. We’re interested in actually solving these problems, not just silencing them.

I agree again. I hate using it and every time is technical debt I know needs fixing.

But it's still a really useful thing to have in your toolbox.

KeithHenry avatar Nov 19 '20 08:11 KeithHenry

I've been a lurker in this issue and its previous iterations, but from what I understand, wouldn't https://github.com/microsoft/TypeScript/issues/13135 solve the entire problem here?

Suppose you could do

type { T1, T2, T3 } = typeof import("./other-file");

this should preserve the non-moduleness of the file but give you a relatively elegant way to re-use many types from other files without importing them.

AlCalzone avatar Nov 19 '20 08:11 AlCalzone

@AlCalzone #13135 would be an alternate fix to #41562 and would be one possible solution here.

However, give that we already have import type { T1, T2, T3 } from "./other-file" (and that kind of means #13135 would now be a corner case and unlikely to get added) I'd rather be able to consistently use that than have different syntaxes for different parts of the same project.

KeithHenry avatar Nov 19 '20 14:11 KeithHenry

The more I think about this, the more I believe it’s not a problem. @KeithHenry, you needed a way to use module types in non-module files, which exists. You replied

As an alternate syntax workaround that works, thanks for letting me know I can import types like that, though I still think it's somewhat confusing and that there is a valid use case for a compiler option/directive.

But I never heard a case for why there is a valid use case for anything further, beyond “I still think it’s somewhat confusing.” The intricacies of module systems is definitely one of the most confusing parts of TypeScript, but even if it’s unintuitive, there are rules and they are working as intended. That means the solution I gave you is not just “an alternative syntax workaround,” it is a different tool with different semantics, and if you’re aware of the rules around modules and the fact that ImportTypeNodes exist, you can put the pieces together and come to that solution. We might have a docs/learning problem here, but that doesn’t mean we need a new compiler option that would further complicate the already confusing module rules.

The other tool that I would propose we can make useful here is fixing --module=none. Currently, it has what I believe to be a bug, where --module=none combined with --target=es2015 or higher (1) does not issue any errors on using imports or exports, and (2) downlevels that module code to CommonJS. This, I believe, is completely incoherent, and has probably not been fixed only because nobody uses --module=none. I think we could justifiably revise the logic here, and use --module=none to enforce that you only use module code that can be elided from emit: basically, import type or any imports that would be allowed to be written as import type, as well as type-only exports. Then, of course, we emit no module marker to the JS under these settings. This would be the appropriate setting to compile all web workers under.

So this leads to lots and lots of tsconfig.json files and me spending more time messing about with config than actually writing code.

I suspect you could work this out so that all workers are compiled under one tsconfig and all browser code is compiled under another, without too much fuss later. I’m somewhat sympathetic to the idea that setting up the correct config for web workers is tedious, but we’re currently talking about an issue of capability and correctness.

andrewbranch avatar Nov 19 '20 18:11 andrewbranch

I tried --module=none and it does export commonjs instead of none. That would be great if it worked. I would be willing to have multiple tsconfig files and have a naming convention for my files like my-file.webworker.ts that I would use an include setting on, like so ["src/**/*.webworker.ts"].

In my use case I have some files that are specifically for the DOM (iifes), some that are modules and some that are pseudo-modules that I created for myself to work with my service worker until we get module support in service workers.

jon49 avatar Nov 21 '20 00:11 jon49

@andrewbranch I really like this idea! module=none removing all import and export from the emitted JS makes loads more sense than treating CommonJS as default. It always seemed weird to me that specifying module=none would create JS that wouldn't run in any browsers, it really should output vanilla JS.

KeithHenry avatar Nov 23 '20 22:11 KeithHenry

I suspect you could work this out so that all workers are compiled under one tsconfig and all browser code is compiled under another, without too much fuss later. I’m somewhat sympathetic to the idea that setting up the correct config for web workers is tedious, but we’re currently talking about an issue of capability and correctness.

Does this mean that it's possible today? We had a TypeScript project with Service Worker source code and as of TypeScript 4.x I see no way or even hack to make it possible to leverage TS types while developing while also outputting valid code for a service worker.

This is what we used previously, until export {} started being injected into the build output:

// @ts-ignore
import {} from "."
declare const self: ServiceWorkerGlobalScope

The above does still make TypeScript use the correct types during development, but there appears to be no way to get it to compile correctly.

Because this came as a bit of a surprise during a huge upgrade to TypeScript 4.1, we had to quickly remove all TypeScript compilation from our service worker codebase (luckily small), so now it's just plain JavaScript with JSDoc for typing.

The alternative solution for others running into this (assuming there's not already something better) might be to have a script remove the export {} line from the built service worker script.

The hack above comes from this issue: https://github.com/microsoft/TypeScript/issues/14877

blixt avatar Dec 30 '20 17:12 blixt

@blixt it sounds like you would benefit from my --module=none proposal. As of today, you’d have to do some more intrusive workarounds to get what you want. If you’re currently importing types into web worker scripts, you’d have to move/copy those types to globals or import them with the const foo: import("./mod").Foo syntax.

andrewbranch avatar Dec 30 '20 18:12 andrewbranch

I don't know what was decided to do with this. But according to this issue 16577:

  • We are not going to implement features, even under a commandline flag, that imply changing JS semantics by rewriting it during emit …
  • We are 100% committed to not rewriting JavaScript code as part of non-downleveling compilation. This is how everything else in TS works; see also this comment in a related feature request, and this comment in a related feature request. We are not going to implement features, even under a commandline flag, that imply changing JS semantics by rewriting it during emit

And another:

Just like for all other things, you should write the JS the way it should be at runtime, and tell TS how to interpret that.

So, if we are to believe those comments then the export {} value should not be created during compilation. If someone needs export {} in their code after TypeScript processing they should add it themselves. This breaks the behavior of the TypeScript that is written and is surprising to the user. The browser understands that a file is a module with no regard to having export {} there or not as that is defined elsewhere (in the script tag).

So, considering what was said on other threads about not changing the JavaScript. This change in TypeScript breaks it promise that we can just write the JS the way it should be at runtime, and tell TS how to interpret that.

jon49 avatar Nov 24 '21 03:11 jon49

My case is the following:

  1. porting some .net fw app to .net core, and I need to rewrite the SignalR part. The .net fw version had a proper index.d.ts out of the box, but with the dotnet core version it is said, that the TS code is 'self-documenting' if imported so no index.d.ts is created by the people on MS payroll.

  2. well if you include the signalr.js client (npm) and want to use SignalR as a type in a TS code all you get is a type error.

  3. what can you do? you try to generate a type definition for yourself from the JS code according to this tutorial All it will output is: export const signalR: {};

  4. by running circles, I've checked out the TS code from github and from npm, and tried the same generation on the source files directly. That was OK, I got the .d.ts files I needed for the whole 50 files or so.

  5. To finally start working on the feature I've done this:

/// <reference path="../typed/signalr.d.ts" />  
/// <reference path="../typed/src/HubConnection.d.ts" />
/// <reference path="../typed/src/HubConnectionBuilder.d.ts" />
import { HubConnection } from "../typed/src/HubConnection";

class _SignalRCient {
   public _connection: HubConnection;
   public StartConnection = async () => {
           [...]
           await this._connection.start();  // finally _connection is a type and it's working
           [...]
   } 
}
  1. I've tried to compile this class as usual to JS and because the export {}; appeared at the end, that's why I'm here.
  2. So I've tried the workarounds I could find (mostly in these github threads):
type HubConnection = typeof import("../typed/src/HubConnection").HubConnection;

and it is not working: TS2339 (TS) Property 'start' does not exist on type 'typeof HubConnection'

it's the same for the generated d.ts file and the source .ts file. So as I see, I have the following options:

A) I go down some unknown road to use the import / export in production that I do not need at all, because I'm forced to do it B) write some quick C# module to eliminate export {}; in the build pipeline C) go with await (this._connection as any).start(); ...why am I even bothering?

I think it is worrying that such simple solutions (try out a feature with the right tooling) is intentionally made overcomplicated by the authors themselves. It's working against being the developer experience inclusive, from my point of view it's getting harder and harder to keep up with this overengineered stuff, even for experienced devs, let alone beginners..

kbalint avatar Jan 05 '22 14:01 kbalint

@kbalint it sounds like you need

- type HubConnection = typeof import("../typed/src/HubConnection").HubConnection;
+ type HubConnection = import("../typed/src/HubConnection").HubConnection;

andrewbranch avatar Jan 05 '22 18:01 andrewbranch

I've read all Andrew Branch's defenses of this change, but I still think the behavior that led to this was user-hostile given that there is no reasonable in-product workaround that seems to work for all cases. That said, it's not difficult to remove the offending line in a post-compile step with this:

sed -i '/export {}/d' .js

It's just a shame that we have to resort to that. I hope that the --module=none proposal gets some traction. Andrew, is there an existing issue for that?

haydentech avatar Jun 03 '22 21:06 haydentech

There is some work in flight to begin making sense of --module none: #48702 (#48790).

The new --moduleDetection flag may also make this issue more tractable, as a lot of the arguments about scope ambiguity and being able to analyze our own outputs vanish under --moduleDetection force. Depending on what scope you expect your files to have, that might be the most promising option. If you’re ok with each file effectively having its own module scope (approximately correct for workers, or any other scripts that will be loaded in isolation), it seems reasonable to set --moduleDetection force, use type-only imports, and maybe we can consider removing the module marker from the output JS in that mode. What I don’t think is on the table is using type-only imports and expecting that file to have global script scope. What’s your use case, @haydentech?

andrewbranch avatar Jun 03 '22 22:06 andrewbranch

maybe we can consider removing the module marker from the output JS in that mode

Actually, it seems like this was discussed at https://github.com/microsoft/TypeScript/issues/47724 and the conclusion was “Ugh.”

andrewbranch avatar Jun 03 '22 22:06 andrewbranch

What I don’t think is on the table is using type-only imports and expecting that file to have global script scope. What’s your use case, @haydentech?

Using type-only imports in a file with global script scope. :-) It's not the end of the world. I'll keep removing the export via sed and move on with my life.

haydentech avatar Jun 24 '22 18:06 haydentech

I don’t understand. If you just use the syntax type Whatever = import("./foo").Whatever, we analyze the file as a global script. This means

  • Top-level declarations are correctly marked as global so you can access them in other scripts.
  • You’ll correctly get an error if you accidentally write a conflicting top-level declaration.

vs. what you’re doing now, where

  • Declarations appear inaccessible across files to TypeScript.
  • Declarations across files can accidentally share the same name, which TypeScript will be fine with but will actually crash at runtime.
  • You need a bespoke post-build transform.

What am I missing here? How is the latter scenario better?

andrewbranch avatar Jun 24 '22 19:06 andrewbranch

What am I missing here? How is the latter scenario better?

If I recall correctly, it has been a while. Is that type Whatever = import("./foo").Whatever imported in more than one file causes issues. TypeScript doesn't like it. So, you are stuck doing it in only 1 file in order to not break your code base. At that point it is pretty useless though.

jon49 avatar Jun 25 '22 09:06 jon49

Just wanted to throw my 2c in that this is also ruining our enterprise project for the same reasons. Stuff like this is why in future projects I went back to normal JS and only incorporating types with JSDoc comments. It's wordy but you don't have to deal with your entire production pipeline screeching to a halt because a TS update broke perfectly valid TS code. JS will always be properly supported, but not TS, React, etc etc.

All sorts of projects are ruined by opinionated decision-makers who think they know what their customers want and correcting for them instead of trusting our intelligence... TS should be a 'dumb' tool that does the job it's set out to do and nothing more, not a smart one that's trying to 'figure out' what we want for us.

Additionally, there's issues with the proposed import("") workaround.

This works:

import A from 'a';
type B = A.B;

But this does not:

type A = import("a") // Module 'a' does not refer to a type, but is used as a type here. Did you mean 'typeof import('a')'?

Sure:

type A = typeof import("a")
type B = A.B // 'A' only refers to a type, but is being used as a namespace here.

ValeTheVioletMote avatar Aug 02 '22 13:08 ValeTheVioletMote

No need to add an extra compiler option. There’s already a module=none option which defaults to CommonJS. TypeScript should use this option to not include any import/export.

SachinShekhar avatar Aug 10 '22 09:08 SachinShekhar

No need to add an extra compiler option. There’s already a module=none option which defaults to CommonJS. TypeScript should use this option to not include any import/export.

We want import directives in the output. We don't always want export because the output file is sometimes a web component (which registers as a side effect) or a worker/service worker (both of which can import modules but crash if trying to export anything).

TS changed to always force an export, I think they just assumed either nobody used workers or everyone that did had separate tsconfig files for each one.

KeithHenry avatar Aug 17 '22 08:08 KeithHenry

Soon it will be 2 year anniversary since devs break a lot of working code with just 1 update. For 2 years they couldn't come up with any trade-off to solve our problem, well-done Microsoft 🤪

Vardner avatar Oct 10 '22 11:10 Vardner

Soon it will be 2 year anniversary since devs break a lot of working code with just 1 update. For 2 years they couldn't come up with any trade-off to solve our problem, well-done Microsoft :zany_face:

this critical issue is among many examples why "TS is just JS but better!" or "TS is a superset of JS" is simply untrue.

I have since moved back to JS and now use JSDoc comments to leverage types where I want them, only where I want them.

ValeTheVioletMote avatar Oct 10 '22 12:10 ValeTheVioletMote

Soon it will be 2 year anniversary since devs break a lot of working code with just 1 update. For 2 years they couldn't come up with any trade-off to solve our problem, well-done Microsoft 🤪

this critical issue is among many examples why "TS is just JS but better!" or "TS is a superset of JS" is simply untrue.

I have since moved back to JS and now use JSDoc comments to leverage types where I want them, only where I want them.

At this point I just use ESBuild to compile my TypeScript code as it doesn't give that issue and is flexible enough for my needs. But I also leverage just simple JSDoc for parts of my code base also.

Yeah, it was an unfortunate decision which was made which broke the assurances they made to the users of TypeScript. I could see making the same mistake too. But I think a mature organization would admit it was a mistake or say they are no longer going to keep the original promise not to add code to your code base.

This change was based off of a tooling problem with a different compilation tool so it seems like a weird decision to me. I still don't understand why they made that decision. But at the same time, I've made plenty of mistakes in my coding life, but I try to own my mistakes though.

jon49 avatar Oct 11 '22 20:10 jon49