Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inferring readonly values in projects with path alias #49408

Closed
hiukky opened this issue Jun 6, 2022 · 7 comments
Closed

inferring readonly values in projects with path alias #49408

hiukky opened this issue Jun 6, 2022 · 7 comments
Assignees
Labels
Unactionable There isn't something we can do with this issue

Comments

@hiukky
Copy link

hiukky commented Jun 6, 2022

Bug Report

🔎 Search Terms

  • Declaration emit widens literal types in readonly properties.

🕗 Version & Regression Information

  • This is a crash no
  • This is the behavior in every version I tried : 4.7.3 and nightly build (4.8.0-dev.20220606)
  • I reviewed the whole FAQ

⏯ Playground Link

Playground link with relevant code

💻 Code

    const instance = {
      program: ts.createSemanticDiagnosticsBuilderProgram,
      host: options?.watch
        ? ts.createSolutionBuilderWithWatchHost
        : ts.createSolutionBuilderHost,
      builder: options?.watch
        ? ts.createSolutionBuilderWithWatch
        : ts.createSolutionBuilder,
    };

    const host = instance.host(
      ts.sys,
      instance.program,
      reportDiagnostic,
      undefined,
      undefined
    );

    const builder = instance.builder(host, options.references, {
      verbose: false,
      incremental: true,
      force: false,
      traceResolution: false,
    });

    builder.build();

🙁 Actual behavior

I was testing a module just now and I noticed that the typescrit was emitting an error that it shouldn't .. I went deeper and saw that the constants were being emitted but only with the type instead of the declared read value.

using tsc -b works as you can see in example 02, but with SolutionBuilder it is setting it to "string" instead of "redBright".

So I don't think it's some option not defined in my tsconfig, because with tsc it outputs as expected, but my implementation with solution builder doesn't.. I also don't see any parameters, or something like that in the solution settings "createSolutionBuilderHost" or "createSolutionBuilder" that relates to that.

image

Looking deeper I decided to compare the tsbuildinfo files, and I noticed this change!
I don't know how TS works under the hood, but I can deduce that this loading order here is causing the problem.

The first example builds using TSC from the command line! it works fine, the second one is using SolutionBuilder and it doesn't issue correctly.

What I can imagine is that in the first case "constants.ts" has already been loaded and is available for "plugin.ts" and with that it can output my reading values.

In the second case "plugin.ts" is being loaded before "constant.ts", so my read values ​​are not available yet, and ts is defaulting to "string".

I tested it twice to see if these values ​​would change in both builds, but they don't..

So that's my logic for that.

I also just encountered this similar issue #15881 but no solution.

Looking at the "build" method we don't have asynchronous code implicit there, so I can assume it's all synchronous, the order of references is also correct.. so I'll try to use other methods like "buildReferences" to see if I get something.

image

🙂 Expected behavior

Correctly issue read-only declarations using SolutionBuilder api.

@hiukky
Copy link
Author

hiukky commented Jun 6, 2022

My configuration using ESNext.

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "node",
    "strict": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "incremental": true,
    "skipLibCheck": true,
    "composite": true,
    "forceConsistentCasingInFileNames": true,
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
}

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Jun 9, 2022
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.8.1 milestone Jun 9, 2022
@hiukky
Copy link
Author

hiukky commented Jun 10, 2022

Adding a little more information, I ended up finding the cause of this when trying to reproduce this in a repository!

I really don't know if this is the expected behavior, but it looks like it's a problem in resolving the ESM modules.

As I'm working on a monorepo, my first (functional) build follows this example:

for pkg in "${sources[@]}"
do
   (
     cd ./"$pkg" \
     && yarn tsc -p tsconfig.build.json \
     && yarn tsc-alias -f
   )
done

The problem here is not that tsc was doing the right job (in this repository I found the same problem), but the tsc-alias! resolving imports with full path .js

Even though I ensure the incremental build order, the modules order is not resolved correctly, and the other cause is mapped paths.

// ✅ It works
import foo from '../foo'

// ❌Already here it breaks
import foo from '@/foo'

Using relative imports works, using paths with custom paths ends up no resolving correctly.

My current solution was this:

image

Before invoking build, I iterate over each project, build individually, resolve the imports so I can move on to the next one and get my build successfully and inferring the types correctly.

So the real problem is that the compiler is not solving the modules in the correct order in incremental mode.

It can solve only from A to A, but not from A < B.

Details:
If the project A uses '../' relative imports:

  • ✅ Emission works correctly in A.
  • ✅ Emission works correctly on B which depends on A.

If the project A uses path alias '@/':

  • ✅ Emission works correctly in A.
  • ❌ Emission does not work correctly on B which depends on A.

I made an example here, you can test for more details.
https://github.com/klaby/ts-solution-builder

@hiukky hiukky changed the title API SolutionBuilder: issuing declarations with read-type properties Inferring readonly values in incremental mode Jun 10, 2022
@hiukky hiukky changed the title Inferring readonly values in incremental mode inferring readonly values in projects with path alias Jun 10, 2022
@sheetalkamat
Copy link
Member

Here is what i tried on your repro:
Created two copies of the repro.
In both i did yarn, followed by npm i typescript@next

After that in first repro i called node node_modules\typescript\lib\tsc.js -b
In another one i called node build.js

Compared both folders and they have same contents except tsbuildinfo which has only diff of dtsDate as expected.

After this i have uncommented imports that were commented and commented out corresponding imports that conflct..
Ran build script and tsc --b and there is no diff again except dts time.

Am i missing something. If yes please provide clear steps on what i would need to reproduce the issue.

Thanks

@sheetalkamat sheetalkamat added Needs More Info The issue still hasn't been fully clarified and removed Needs Investigation This issue needs a team member to investigate its status. labels Jun 24, 2022
@sheetalkamat sheetalkamat assigned hiukky and unassigned sheetalkamat Jun 24, 2022
@hiukky
Copy link
Author

hiukky commented Jun 24, 2022

@sheetalkamat did you look at packages/foo/dist/src/sample/index.d.ts and packages/bar/dist/src/sample/index.d.ts before and after switching imports?

I'll try to describe it better!

@sheetalkamat
Copy link
Member

I did .. I compared the folders and every output was same except tsbuildinfo

@hiukky
Copy link
Author

hiukky commented Jun 24, 2022

can you look again? I just updated the repository

@sheetalkamat
Copy link
Member

Looked at your modified repro and as per that issue is not with invoking solutionBuilder but just tsc corect.
I looked at your config for foo and it is incorrectly configured. "@/color" and "@/types" in dist/src/helpers/index.d.ts do not get resolved per traceResolutions because it the path mapping is configured incorrectly.

======== Resolving module '@/color' from 'C:/temp/ts-solution-builder/packages/bar/dist/src/helpers/index.d.ts'. ========
Explicitly specified module resolution kind: 'NodeJs'.
'baseUrl' option is set to 'c:/temp/ts-solution-builder/packages/foo', using this value to resolve non-relative module name '@/color'.
'paths' option is specified, looking for a pattern to match module name '@/color'.
Module name '@/color', matched pattern '@/*'.
Trying substitution './src/*', candidate module location: './src/color'.
Loading module as file / folder, candidate module location 'c:/temp/ts-solution-builder/packages/foo/src/color', target file type 'TypeScript'.
File 'c:/temp/ts-solution-builder/packages/foo/src/color.ts' does not exist.
File 'c:/temp/ts-solution-builder/packages/foo/src/color.tsx' does not exist.
File 'c:/temp/ts-solution-builder/packages/foo/src/color.d.ts' does not exist.
Directory 'c:/temp/ts-solution-builder/packages/foo/src/color' does not exist, skipping all lookups in it.
Loading module '@/color' from 'node_modules' folder, target file type 'TypeScript'.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/helpers/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Directory 'C:/temp/ts-solution-builder/packages/bar/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Directory 'C:/temp/ts-solution-builder/packages/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Scoped package detected, looking in '__color'
File 'C:/temp/ts-solution-builder/node_modules/@types/__color.d.ts' does not exist.
Directory 'C:/temp/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
Directory 'C:/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in '__color'
'baseUrl' option is set to 'c:/temp/ts-solution-builder/packages/foo', using this value to resolve non-relative module name '@/color'.
'paths' option is specified, looking for a pattern to match module name '@/color'.
Module name '@/color', matched pattern '@/*'.
Trying substitution './src/*', candidate module location: './src/color'.
Loading module as file / folder, candidate module location 'c:/temp/ts-solution-builder/packages/foo/src/color', target file type 'JavaScript'.
File 'c:/temp/ts-solution-builder/packages/foo/src/color.js' does not exist.
File 'c:/temp/ts-solution-builder/packages/foo/src/color.jsx' does not exist.
Directory 'c:/temp/ts-solution-builder/packages/foo/src/color' does not exist, skipping all lookups in it.
Loading module '@/color' from 'node_modules' folder, target file type 'JavaScript'.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/helpers/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/node_modules' does not exist, skipping all lookups in it.
'baseUrl' option is set to 'c:/temp/ts-solution-builder/packages/foo', using this value to resolve non-relative module name '@/color'.
'paths' option is specified, looking for a pattern to match module name '@/color'.
Module name '@/color', matched pattern '@/*'.
Trying substitution './src/*', candidate module location: './src/color'.
Loading module as file / folder, candidate module location 'c:/temp/ts-solution-builder/packages/foo/src/color', target file type 'Json'.
Directory 'c:/temp/ts-solution-builder/packages/foo/src/color' does not exist, skipping all lookups in it.
Loading module '@/color' from 'node_modules' folder, target file type 'Json'.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/helpers/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/src/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/dist/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/bar/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/ts-solution-builder/packages/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/temp/node_modules' does not exist, skipping all lookups in it.
Directory 'C:/node_modules' does not exist, skipping all lookups in it.
======== Module name '@/color' was not resolved. ========

I think you want to use reference to bar project in tsconfig for foo to be able to correctly resolve the imports and then things work correctly as it would use bar/tsconfig.json to do the mappings.

======== Resolving module '@/color' from 'C:/temp/ts-solution-builder/packages/bar/dist/src/helpers/index.d.ts'. ========
Using compiler options of project reference redirect 'c:/temp/ts-solution-builder/packages/bar/tsconfig.json'.
Explicitly specified module resolution kind: 'NodeJs'.
'baseUrl' option is set to 'c:/temp/ts-solution-builder/packages/bar', using this value to resolve non-relative module name '@/color'.
'paths' option is specified, looking for a pattern to match module name '@/color'.
Module name '@/color', matched pattern '@/*'.
Trying substitution './src/*', candidate module location: './src/color'.
Loading module as file / folder, candidate module location 'c:/temp/ts-solution-builder/packages/bar/src/color', target file type 'TypeScript'.
File 'c:/temp/ts-solution-builder/packages/bar/src/color.ts' does not exist.
File 'c:/temp/ts-solution-builder/packages/bar/src/color.tsx' does not exist.
File 'c:/temp/ts-solution-builder/packages/bar/src/color.d.ts' does not exist.
File 'c:/temp/ts-solution-builder/packages/bar/src/color/package.json' does not exist.
File 'c:/temp/ts-solution-builder/packages/bar/src/color/index.ts' exist - use it as a name resolution result.
======== Module name '@/color' was successfully resolved to 'c:/temp/ts-solution-builder/packages/bar/src/color/index.ts'. ========

@sheetalkamat sheetalkamat assigned sheetalkamat and unassigned hiukky Jun 27, 2022
@sheetalkamat sheetalkamat added External Relates to another program, environment, or user action which we cannot control. Unactionable There isn't something we can do with this issue and removed Needs More Info The issue still hasn't been fully clarified External Relates to another program, environment, or user action which we cannot control. labels Jun 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Unactionable There isn't something we can do with this issue
Projects
None yet
Development

No branches or pull requests

3 participants