Open Dunqing opened 3 weeks ago
This came from trying to align oxc's ID implementation in vue.
To reproduce:
import {
Comment,
} from './vnode'
export enum DOMNodeTypes {
ELEMENT = 1,
TEXT = 3,
COMMENT = 8,
}
export const isComment = (node: Node): node is Comment =>
node.nodeType === DOMNodeTypes.COMMENT
Is IDed to
import { type VNode } from './vnode';
export declare enum DOMNodeTypes {
ELEMENT = 1,
TEXT = 3,
COMMENT = 8
}
export declare const isComment: (node: Node) => node is Comment;
Very confusingly, the actual usage for the imported Comment
is in https://github.com/vuejs/core/blob/a177092754642af2f98c33a4feffe8f198c3c950/packages/runtime-core/src/hydration.ts#L198. Comment
in node is Comment
is resolved to the one in lib.dom.d.ts
We are unable to implementation this behavior in oxc due to the lack of type checker.
Edit: I ended up patching vue: https://github.com/vuejs/core/pull/12009
The root issue is that in isolated declaration mode we can't know if an import is a type or a value. The good news is that it should not matter for declaration emit, the only potential side effect is that we might leave an unused import in the declaration file. Let's consider the possibilities:
import { Comment } from '@vue/runtime-core'
export const comment: Comment
Comment
always refers to the import so it should be keptComment
refers to the import so it should be kept in the file. Comment
refers to the global. However if we preserve the import, we still have a valid declaration (one with an unused import, but that is not an error)The conclusion is that if we have an import, that is referenced from a type or value position it is always valid to keep it even if we don't know for sure if typescript actually resolves to the import or to some unseen global.
Ideally we will align the TS declaration emit to be the same as what a tool without type information will output (and keep the import, even if we know it to be unused), but even if they are different the no type checking tool can produce a valid declaration.
Acknowledgement
Example
Playground Link
This example is correct because the
tsc
checker analyzerComment
is a const variable defined in@vue/runtime-core
. So theComment
who referenced bycomment
is actually referenced lib.dom.d.ts'sComment
. But the output of this example intranspileDeclaration
APi will same as the following example.Another example
Playground Link
This example is also correct because the
tsc
checker can't analyze whatComment
is, so theComment
was kept in the output as it has been referenced bycomment
.But If I want to use lib.dom.d.ts's
Comment
rather than imported it will be incorrect.Expect Behaviour
In
IsolatedDeclarations
, Ideally, we shouldn't analyze imports, but if we stop analyzing, this will generate incorrect output.So I suggest
tsc
should throw an error about the above cases whenIsolatedDeclarations
is enabled. This is also beneficial for third-partyIsolatedDeclarations
implementations.BTW this issue I found when I fix the output mismatch between
oxc-isolated-declarations
andtsc