Skip to content

Commit

Permalink
fix(semantic): incorrect resolve references for TSTypeQuery (#4310)
Browse files Browse the repository at this point in the history
```ts
type A = typeof Foo
                ^^^ Only allow reference to value symbol
```

I have verified the changed snapshot. That's correct
  • Loading branch information
Dunqing committed Jul 17, 2024
1 parent 48724a0 commit 351ecf2
Show file tree
Hide file tree
Showing 17 changed files with 140 additions and 83 deletions.
96 changes: 56 additions & 40 deletions crates/oxc_linter/src/rules/typescript/consistent_type_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,23 @@ fn is_only_has_type_references(symbol_id: SymbolId, ctx: &LintContext) -> bool {
if peekable_iter.peek().is_none() {
return false;
}
peekable_iter.all(oxc_semantic::Reference::is_type)
peekable_iter.all(|reference| {
if reference.is_type() {
return true;
} else if reference.is_read() {
for node in ctx.nodes().iter_parents(reference.node_id()).skip(1) {
return match node.kind() {
// CASE 1:
// `type T = typeof foo` will create a value reference because "foo" must be a value type
// however this value reference is safe to use with type-only imports
AstKind::TSTypeQuery(_) => true,
AstKind::TSTypeName(_) | AstKind::TSQualifiedName(_) => continue,
_ => false,
};
}
}
false
})
}

struct FixOptions<'a, 'b> {
Expand Down Expand Up @@ -1155,7 +1171,7 @@ fn test() {
(
"
import Type from 'foo';
export { Type }; // is a value export
export default Type; // is a value export
",
Expand All @@ -1164,7 +1180,7 @@ fn test() {
(
"
import type Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1174,7 +1190,7 @@ fn test() {
(
"
import { Type } from 'foo';
export { Type }; // is a value export
export default Type; // is a value export
",
Expand All @@ -1183,7 +1199,7 @@ fn test() {
(
"
import type { Type } from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1193,7 +1209,7 @@ fn test() {
(
"
import * as Type from 'foo';
export { Type }; // is a value export
export default Type; // is a value export
",
Expand All @@ -1202,7 +1218,7 @@ fn test() {
(
"
import type * as Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1212,7 +1228,7 @@ fn test() {
(
"
import Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1222,7 +1238,7 @@ fn test() {
(
"
import { Type } from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1232,7 +1248,7 @@ fn test() {
(
"
import * as Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand Down Expand Up @@ -1282,7 +1298,7 @@ fn test() {
(
"
import type * as constants from './constants';
export type Y = {
[constants.X]: ReadonlyArray<string>;
};
Expand Down Expand Up @@ -1796,31 +1812,31 @@ fn test() {
(
"
import Type from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import { Type } from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import * as Type from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import type Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1830,7 +1846,7 @@ fn test() {
(
"
import type { Type } from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1840,7 +1856,7 @@ fn test() {
(
"
import type * as Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -1853,7 +1869,7 @@ fn test() {
import type // comment
DefType from 'foo';
import type /*comment*/ { Type } from 'foo';
type T = { a: AllType; b: DefType; c: Type };
",
Some(serde_json::json!([{ "prefer": "no-type-imports" }])),
Expand Down Expand Up @@ -1933,7 +1949,7 @@ fn test() {
(
"
import { A, B } from 'foo';
let foo: A;
B();
",
Expand Down Expand Up @@ -2028,7 +2044,7 @@ fn test() {
"
import { A, B, C } from 'foo';
import type { D } from 'deez';
const foo: A = B();
let bar: C;
let baz: D;
Expand Down Expand Up @@ -2132,7 +2148,7 @@ fn test() {
class A {
@deco
get foo() {}
set foo(value: Foo) {}
}
",
Expand All @@ -2144,7 +2160,7 @@ fn test() {
class A {
@deco
get foo() {}
set ['foo'](value: Foo) {}
}
",
Expand Down Expand Up @@ -2660,53 +2676,53 @@ fn test() {
(
"
import Type from 'foo';
export type { Type }; // is a type-only export
",
"
import type Type from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import { Type } from 'foo';
export type { Type }; // is a type-only export
",
"
import type { Type } from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import * as Type from 'foo';
export type { Type }; // is a type-only export
",
"
import type * as Type from 'foo';
export type { Type }; // is a type-only export
",
None,
),
(
"
import type Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
",
"
import Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -2716,14 +2732,14 @@ fn test() {
(
"
import type { Type } from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
",
"
import { Type } from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -2733,14 +2749,14 @@ fn test() {
(
"
import type * as Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
",
"
import * as Type from 'foo';
export { Type }; // is a type-only export
export default Type; // is a type-only export
export type { Type }; // is a type-only export
Expand All @@ -2753,15 +2769,15 @@ fn test() {
import type // comment
DefType from 'foo';
import type /*comment*/ { Type } from 'foo';
type T = { a: AllType; b: DefType; c: Type };
",
"
import /*comment*/ * as AllType from 'foo';
import // comment
DefType from 'foo';
import /*comment*/ { Type } from 'foo';
type T = { a: AllType; b: DefType; c: Type };
",
Some(serde_json::json!([{ "prefer": "no-type-imports" }])),
Expand Down Expand Up @@ -2890,13 +2906,13 @@ fn test() {
(
"
import { A, B } from 'foo';
let foo: A;
B();
",
"
import { type A, B } from 'foo';
let foo: A;
B();
",
Expand Down Expand Up @@ -3036,15 +3052,15 @@ fn test() {
"
import { A, B, C } from 'foo';
import type { D } from 'deez';
const foo: A = B();
let bar: C;
let baz: D;
",
"
import { type A, B, type C } from 'foo';
import type { D } from 'deez';
const foo: A = B();
let bar: C;
let baz: D;
Expand Down
Loading

0 comments on commit 351ecf2

Please sign in to comment.