100pah opened a new pull request, #20030: URL: https://github.com/apache/echarts/pull/20030
<!-- Please fill in the following information to help us review your PR more efficiently. --> ## Brief Information This pull request is in the type of: - [x] bug fixing - [ ] new feature - [ ] others ### What does this PR do? <!-- USE ONE SENTENCE TO DESCRIBE WHAT THIS PR DOES. --> Fix that In users' .d.ts `import('echarts/types/dist/shared')` can not visit `'echarts/types/dist/shared.d.ts'` since v5.5.0. ### Fixed issues Fix #19663 . Relative issues: https://github.com/ecomfe/vue-echarts/issues/766 , https://github.com/apache/echarts/pull/19513 ## Details ### Before: What was the problem? In users' .d.ts `import('echarts/types/dist/shared')` can not visit `'echarts/types/dist/shared.d.ts'` since v5.5.0. It cause that users can only get type `any` when import echarts type. ### After: How does it behave after the fixing? After some investigate to `tsc`, I found that: Test case (tested in typescript v5.3.3) : + Case_A: ```ts /** @file main1.ts (user's source ts files) */ import { init } from "echarts/core"; type EChartsType1 = ReturnType<typeof init>; export let option = {} as EChartsType1; ``` ```ts /** @file main1.d.ts (tsc generated d.ts file) */ // Has inline import() generated, and refer deeply to "echarts/types/dist/shared", // in which `EChartsType` is declared literally. export declare let option: import("echarts/types/dist/shared").EChartsType; ``` + Case_B: ```ts /** @file main2.ts (user's source ts files) */ import { init } from "echarts/core"; type InitType = typeof init; type EChartsType1 = ReturnType<InitType>; export let option: EChartsType1; // This is the only difference from "main1.ts". ``` ```ts /** @file main1.d.ts (tsc generated d.ts file) */ // No inline import() generated. import { init } from "echarts/core"; type EChartsType1 = ReturnType<typeof init>; export declare let option: EChartsType1; export {}; ``` In the case about we can found that: + `tsc` may generate "inline import" (i.e., `import(xxx/xxx/xxx)`) or not. + In face `tsc` may intentionally generate inline import to avoid to handle name collision. see <https://github.com/microsoft/TypeScript/issues/30258#issuecomment-470727688> <https://github.com/microsoft/TypeScript/issues/36097#issuecomment-582668813>. + When generate inline import `import(xxx/xxx/xxx)`, the path `xxx/xxx/xxx` probably goes deep into the file where the target type declared literally defined, but may not consider its visibility defined in "exports" field of `package.json`. + Take the Case_A above as am example, the target type need to be resolved is `EChartsType` from the last sentence `export let option = {} as EChartsType1;`, and `EChartsType` is declared in `echarts/types/dist/shared.d.ts`, the final inline import is `import('echarts/types/dist/shared')` or `import('echarts/types/dist/shared.js')`, although `echarts/types/dist/shared` seems to be a private file and imported by `echarts/core.d.ts`. + There is some investigation into the source code of `tsc`. It's verbose, just for the record: + When travel and parse ts file starting from [`transformRoot`](https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/transformers/declarations.ts#L486), + in which [`function symbolToTypeNode`](https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/checker.ts#L7974) is called to resolve the literal type `EChartsType1` of the sentence `export let option = {} as EChartsType1;`, + in which `lookupSymbolChain` is called to use the input `symbol(of "EChartsType")` to get a chain like `[symbol(of "dist/shared.d.ts"), symbol(of "EChartsType")]`, and generate a specifier for `chain[0]`, and call `const lit = factory.createLiteralTypeNode(factory.createStringLiteral(specifier));` to create a literal node containing the path 'xxx/dist/shared', and call `return factory.createImportTypeNode(lit, ...)` to return a new type node on which the literal node is mounted. + So for the original type node "EChartsType" has been resolved the a type node "xxx/dist/shared". + Finally in [`writeKeyword("import"); writePunctuation("("); emit(node.argument);`](https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/emitter.ts#L2949) the literal node of 'xxx/dist/shared' generated above is in the `node.argument` and be used to write as `import('xxx/dist/shared')`. + Both `ambient module declaration file` or `normal module file` has the same behavior. ```ts /** @file echarts/core.d.ts (An ambient module declarataion file) */ declare module "echarts/core" { export * from 'echarts/types/dist/core'; } ``` ```ts /** @file echarts/core.d.ts (An normal module file) */ export * from './types/dist/core'; ``` + Either `import('echarts/types/dist/shared')` or `import('echarts/types/dist/shared.js')` can be generated by `tsc`. I don't known the rule yet. + For the case `import('echarts/types/dist/shared.js')`: although this file does not exist, it seems OK in d.ts file to used it, `tsc` can resolve it back to `echarts/types/dist/shared.d.ts`. + For the case `import('echarts/types/dist/shared')`: this is case of the bug https://github.com/apache/echarts/pull/19513 . Since echarts v5.5.0, `echarts/types/dist/shared` is not visible from outside. So this PR make it visible by add it to the "exports" field of `package.json`. ## Other infomation In <https://cdn.jsdelivr.net/npm/vue-echarts@6.7.3/dist/index.d.ts> there are both `import("echarts/types/dist/shared")` and `import("echarts/types/dist/echarts")`. It because in <https://github.com/ecomfe/vue-echarts/blob/v6.7.3/src/types.ts#L2> both from 'echarts/core' and 'echarts'. ```ts import { init } from "echarts/core"; import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts"; ``` It's OK, but it probably be better a little if all of them are `from 'echarts/core'`, @Justineo . -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org