2

I'm working on a project that was originally written in plain Javascript. I've added a Typescript folder at the root level which contains the same structure as the original javascript. The filestructure looks like this:

|_ build
|  |_ automatically generated js files from Meta and src using build command
|
|_ meta
|  |_ foo.js, bar.js
|
|_ src
|  |_ baz.js
|
|_ typescript
|  |_ meta
|     |_ foo.ts, bar.ts
|  |_ src
|     |_ baz.ts

When I run tsc, I'd like all of the Typescript files within the typescript directory to compile out to the same structure they existed in in the Typescript directory to the root directory. However, most of the examples I've seen using the outDir have things building to a specific build folder.

{
  "compilerOptions": {
    "sourceMap": false,
    "noImplicitAny": true,
    "module": "es6",
    "moduleResolution": "node",
    "allowJs": true,
    "target": "ES2020",
    "lib": ["ES2018"],
    "allowSyntheticDefaultImports": true
    "outDir" : "" // what can be here to say "use include file structure - typescript dir?
  },
  "exclude": ["node_modules"],
  "include": ["typescript/**/*"]
}

I cannot wrap the Javascript directories into a "dist" folder. How should I structure my tsconfig to build to the root level, matching the same directories inside the typescript directory?

13
  • I just want to make sure I understand the directory layout you want. For example, where should typescript/src/baz.ts live once it has been compiled into baz.js ? Commented Mar 9, 2020 at 23:19
  • Are there source files in meta and src, or are those strictly output directories for the compiled typescript? Commented Mar 9, 2020 at 23:32
  • Do the source files inside typescript folder import original files from meta and src or are they completely independent? Note that they would overwrite existent js sources with equal names. Commented Mar 10, 2020 at 6:08
  • @ford04 I think there are no files in meta and src, based on the directory structure above, because the .js files in meta and src match the names of those under the typescript directory. I'm not sure, though. Commented Mar 10, 2020 at 7:53
  • 1
    @ford04 That works perfectly! Could you write that up as an answer so I can give you the bounty? Thanks!! Commented Mar 10, 2020 at 16:57

2 Answers 2

2
+50

To recap your requirements:

|_ meta // emit js files for typescript/meta here
|_ src  // emit js files for typescript/src here
|_ typescript // root folder for all .ts source files
|  |_ meta
|     |_ foo.ts, bar.ts
|  |_ src
|     |_ baz.ts

To do that, we can adjust tsconfig.json:

{
  "compilerOptions": {
    // ...
    "outDir": ".",
    "rootDir": "typescript"
  },
  "include": ["typescript/**/*"],
  "exclude": ["node_modules", "src", "meta", "build"],
}

Then all input .ts files will be emitted in the following path (relative to tsconfig.json):

emit-path: <outDir>/<filePath> minus <rootDir>  (rootDir chopped off from file path)

Example: ./typescript/src/baz.ts  -->  ./src/baz.js

We could leave out the rootDir config option:

Default: The longest common path of all non-declaration input files. When TypeScript compiles files, it keeps the same directory structure in the output directory as exists in the input directory.

Though it is a good practice to make it explicit, so the compiler will trigger an error, if something is wrong with the location of the input files.

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

8 Comments

I get an error whenever the output directory contains the source files
$ tsc --version: Version 3.8.3. error TS18003: No inputs were found in config file
That is why you also specify the additional "exclude" entries. Above will exclude src and meta, which are the emit folders for OP.
Yes I just tried with the exclude and it works. Nice job. (I still think compiling to another source folder is a really bad approach, however)
Ah gotcha. I noticed that tsc doesn't throw an error if I remove meta and src from the exclusions, so I wasn't sure if it was handling the way you anticipated. Thanks for the information.
|
-1

Summary

The answer is no. (At least not with a single build step/config)

This is possible, see ford04's answer.

Why this is a bad idea

  1. Your output artifacts are now mingled with other source/input artifacts. Why is this bad? Consider what would happen if you deleted a folder under typescript/src, for example typescript/src/some-utils. Because it has already compiled, this folder and all of the compiled source files under it already exists in the src/some-utils directory. Next compilation, they will still be there. How can we clean this? Normally, a "clean" step exists before build, and it will simply delete the output directoy and recompile. But now there are source files in the src!

    We have no easy way of distinguishing source files and typescript output files. We could delete the src directory and then git checkout -- src to restore the source files. But what if we were in the middle of editing some files? I suppose we could stash our changes: git stash; rm -rf src; git checkout -- src; git stash pop;. But untracked files are still lost! Ok.. git add src; git stash; rm -rf src; git checkout -- src; git stash pop; git restore --staged src. This fixes things, mostly, but any staged files we have are still unstaged. You can see how complicated this has become.

    But there is an additional and more serious problem with this layout. We can't .gitignore any Typescript file, so Git will constantly show untracked files. There is no way to detect if someone accidentally commits a compiled Typescript file. The problem may become compounded if someone attempts to make changes to a committed compiled Typescript file. These changes will be overwritten by the Typescript compiler on each run, and the changes will be lost.

  2. You have source roots at two levels with the folder hierarchy. Conceptually, these should be at the same level, and all of your source files should be in one folder.

A better approach

When migrating Javascript to Typescript, a good approach is to start by adding Typescript annotations to the Javascript files. This way, you keep all of the advantages of Typescript without adding any complexity to your process. When a Javascript file is nearly fully annotated, convert it into a Typescript .ts file (this enforces the use of Typescript for any changes to this file in the future), but leave it alongside the Javascript files. Then, when compiling, simply set allowJs to true and the Typescript compiler will happily output all of your Javascript files to the Typescript output directory.

You mentioned that you cannot wrap your Javascript files into a dist or any output/build folder, but it's not clear why. This seems like the major blocker in moving forward with this.

3 Comments

Thank you for the input, I really appreciate hearing this perspective.
This project is being used as a POC on a legacy repo. The company may decide to not use TS. As a result, it is necessary to implement this without changing any other part of the build process, which includes the file structure. This is why the TS files we are testing out to replace the current works are kept separately. One of the biggest points is that we don't want to distinguish between the legacy src and the new output, to show how typescript won't uproot our previous styles. Hopefully this makes sense.
@rDev, that's what I figured. I worry that such a proof-of-concept would actually cause people to reject it due to the points I highlighted (I personally would reject such a setup). I outlined the other approaches which may work better. I'm glad if this perspective is helpful to you (although in that case I'm not sure why the downvote). Best of luck either way !

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.