dsherret / ts-morph

TypeScript Compiler API wrapper for static analysis and programmatic code changes.
https://ts-morph.com
MIT License
4.87k stars 194 forks source link

Does ts-morph supports "reference" in typescript? #1528

Open JCDenton47 opened 4 months ago

JCDenton47 commented 4 months ago

Describe the bug

Version: 21.0.1

I am trying to use ts-morph apis to create a simple type-checker app.

With projects using project reference, the "app" will always resolve type definition from lib's ts source file instead of declaration

To Reproduce

I have created a demo project here, maintainers can reproduce the problem by

  1. clone repo
  2. pnpm install
  3. npx tsc
  4. node src/index.js (invoke ts-morph to do the type-check)
  5. node src/tsc.js (invoke tsc to do the type-check)

As you can see, the demo project's structure is

image nodeApp's tsconfig

{

  "compilerOptions": {

    "target": "ES2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
    "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,

    "strict": true /* Enable all strict type-checking options. */,
    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
    /* Module Resolution Options */
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,

    "types": [],                           /* Type declaration files to be included in compilation. */
    "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,

    "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
    "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
    /* Advanced Options */
    "skipLibCheck": true /* Skip type checking of declaration files. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
    "resolveJsonModule": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]
    },
    "outDir": "dist",
    "rootDir": "",
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true
  },
  "references": [
    {
      "path": "../nodeLib"
    }
  ]
}

nodeLib's tsconfig

{
  "compilerOptions": {
    "target": "ES2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
    "module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,

    "strict": true /* Enable all strict type-checking options. */,
    "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
    /* Module Resolution Options */
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,

    "types": [] /* Type declaration files to be included in compilation. */,
    "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,

    "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
    "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
    /* Advanced Options */
    "skipLibCheck": true /* Skip type checking of declaration files. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
    "resolveJsonModule": true,
    "baseUrl": "./",
    "paths": {
      "@/*": ["./src/*"]
    },
    "outDir": "dist",
    "rootDir": "",
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    "composite": true
  }
}

nodeApp has a project reference pointed to nodeLib

nodeLib/index.ts is added with type-errors

//nodeLib/index.ts
export function someFuncWithError() {
  let a: string = 1;
}

nodeApp/index.ts is clean

import { someFuncWithError } from '../nodeLib';

export {};

I wrote a very simple script to try to report errors in nodeApp

import { Project } from 'ts-morph'
import path from 'path'

const project = new Project(
  {
    tsConfigFilePath: `fixtures/nodeApp/tsconfig.json`,
  }
);

const diagnostics = project.getPreEmitDiagnostics()

console.log(project.formatDiagnosticsWithColorAndContext(diagnostics))

It reports with the following error image

It seems it is still trying to compile the reference files, however with project reference, it should read type info from declaration files

Expected behavior Returns result the same as tsc api If we use tsc API to run type-check on nodeApp, it will report image It's correct since we didn't build the nodeLib, if we run tsc on nodeLib and run tsc api again, no error would report image

zFitness commented 4 months ago

This happened to me, too, in my vue project:

image image image image