Typescript, Decorators in sub-folders of in-repo add-ons

We develop many ember apps for different clients and have adopted a coding approach in our ember development process where reusable aspects of projects are put into an in-repo add-on to help maintain abstraction, encapsulation, and in many cases, to make them easier to extract into external add-ons for re-use in other projects.

We also use Typescript, and we have two current lint issues that arise during use of VS Code during development:

  • The first is that the export within each file under the app folder in each add-on always highlights a “Cannot find module ‘my-addon/file-being-imported’ or its corresponding type declarations” error - our overall tsconfig does have the proper paths entry
  • The second is that any use of decorators in the in-repo add-on at the top level of the addon folder is fine, but any use in a subfolder is not, unless that subfolder is imported into a top-level folder (by creating an index.d.ts file for example) - we see the old “Experimental support for decorators… ts(1219)” error - it’s as though Typescript doesn’t know this file is part of the project, and perhaps that’s because the generator for the tsconfig has paths for “my-addon” and “my-addon/*” but not “my-addon/**” which, it turns out, is illegal.

None of this stops successful compilation, but it has the effect of burying real lint issues in the IDE underneath hundreds of spurious errors.

Hoping there’s a “quick-fix” to both issues.

It’s technically not supported to put TypeScript files in the app folder of an addon. The ember-cli-typescript docs say:

Because addons have no control over how files in app/ are transpiled, you cannot have .ts files in your addon’s app/ folder .

in-repo addons let you escape this restriction a bit, because the app has control over how these folders will transpile and you can ensure the app supports typescript, but in practice this is still confusing for typescript because the app tree files do an uncanny thing where they really live in the app’s module namespace, not the addon’s.

So one option is to stick to the default convention and keep app-tree files as JS, not TS. Alternatively, you would need to teach typescript that it’s OK for a package to resolve its own name. This is actually allowed in modern Node versions if a package uses the exports key in package.json, but TypeScript doesn’t support that yet.