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

Reply via email to