Skip to content

Commit f07077c

Browse files
authored
Fixed a redundant used before defined error (#55283)
1 parent 769f2da commit f07077c

File tree

4 files changed

+132
-6
lines changed

4 files changed

+132
-6
lines changed

src/compiler/checker.ts

+5-6
Original file line numberDiff line numberDiff line change
@@ -2773,6 +2773,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
27732773
return sourceFiles.indexOf(declarationFile) <= sourceFiles.indexOf(useFile);
27742774
}
27752775

2776+
// deferred usage in a type context is always OK regardless of the usage position:
2777+
if (!!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || isInAmbientOrTypeNode(usage)) {
2778+
return true;
2779+
}
2780+
27762781
if (declaration.pos <= usage.pos && !(isPropertyDeclaration(declaration) && isThisProperty(usage.parent) && !declaration.initializer && !declaration.exclamationToken)) {
27772782
// declaration is before usage
27782783
if (declaration.kind === SyntaxKind.BindingElement) {
@@ -2813,9 +2818,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
28132818
// (except when emitStandardClassFields: true and the reference is to a parameter property)
28142819
// 4. inside a static property initializer, a reference to a static method in the same class
28152820
// 5. inside a TS export= declaration (since we will move the export statement during emit to avoid TDZ)
2816-
// or if usage is in a type context:
2817-
// 1. inside a type query (typeof in type position)
2818-
// 2. inside a jsdoc comment
28192821
if (usage.parent.kind === SyntaxKind.ExportSpecifier || (usage.parent.kind === SyntaxKind.ExportAssignment && (usage.parent as ExportAssignment).isExportEquals)) {
28202822
// export specifiers do not use the variable, they only make it available for use
28212823
return true;
@@ -2825,9 +2827,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
28252827
return true;
28262828
}
28272829

2828-
if (!!(usage.flags & NodeFlags.JSDoc) || isInTypeQuery(usage) || isInAmbientOrTypeNode(usage)) {
2829-
return true;
2830-
}
28312830
if (isUsedInFunctionOrInstanceProperty(usage, declaration)) {
28322831
if (
28332832
emitStandardClassFields
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//// [tests/cases/compiler/noUsedBeforeDefinedErrorInTypeContext.ts] ////
2+
3+
=== noUsedBeforeDefinedErrorInTypeContext.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/8775
5+
6+
interface IThing<T> {
7+
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
8+
>T : Symbol(T, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 17))
9+
10+
owner: T;
11+
>owner : Symbol(IThing.owner, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 21))
12+
>T : Symbol(T, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 17))
13+
}
14+
15+
var foo = {
16+
>foo : Symbol(foo, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 3))
17+
18+
one: {} as IThing<typeof foo>,
19+
>one : Symbol(one, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 11))
20+
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
21+
>foo : Symbol(foo, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 3))
22+
}
23+
24+
let baz = {
25+
>baz : Symbol(baz, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 10, 3))
26+
27+
two: {} as IThing<typeof bar>,
28+
>two : Symbol(two, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 10, 11))
29+
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
30+
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
31+
}
32+
33+
let bar = {
34+
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
35+
36+
three: {} as IThing<typeof bar>,
37+
>three : Symbol(three, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 11))
38+
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
39+
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
40+
}
41+
42+
const qwe = {
43+
>qwe : Symbol(qwe, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 5))
44+
45+
four: {} as IThing<typeof qwe>,
46+
>four : Symbol(four, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 13))
47+
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
48+
>qwe : Symbol(qwe, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 5))
49+
}
50+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//// [tests/cases/compiler/noUsedBeforeDefinedErrorInTypeContext.ts] ////
2+
3+
=== noUsedBeforeDefinedErrorInTypeContext.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/8775
5+
6+
interface IThing<T> {
7+
owner: T;
8+
>owner : T
9+
}
10+
11+
var foo = {
12+
>foo : any
13+
>{ one: {} as IThing<typeof foo>,} : { one: IThing<any>; }
14+
15+
one: {} as IThing<typeof foo>,
16+
>one : IThing<any>
17+
>{} as IThing<typeof foo> : IThing<any>
18+
>{} : {}
19+
>foo : any
20+
}
21+
22+
let baz = {
23+
>baz : { two: IThing<any>; }
24+
>{ two: {} as IThing<typeof bar>,} : { two: IThing<any>; }
25+
26+
two: {} as IThing<typeof bar>,
27+
>two : IThing<any>
28+
>{} as IThing<typeof bar> : IThing<any>
29+
>{} : {}
30+
>bar : any
31+
}
32+
33+
let bar = {
34+
>bar : any
35+
>{ three: {} as IThing<typeof bar>,} : { three: IThing<any>; }
36+
37+
three: {} as IThing<typeof bar>,
38+
>three : IThing<any>
39+
>{} as IThing<typeof bar> : IThing<any>
40+
>{} : {}
41+
>bar : any
42+
}
43+
44+
const qwe = {
45+
>qwe : any
46+
>{ four: {} as IThing<typeof qwe>,} : { four: IThing<any>; }
47+
48+
four: {} as IThing<typeof qwe>,
49+
>four : IThing<any>
50+
>{} as IThing<typeof qwe> : IThing<any>
51+
>{} : {}
52+
>qwe : any
53+
}
54+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// @noEmit: true
2+
3+
// https://github.com/microsoft/TypeScript/issues/8775
4+
5+
interface IThing<T> {
6+
owner: T;
7+
}
8+
9+
var foo = {
10+
one: {} as IThing<typeof foo>,
11+
}
12+
13+
let baz = {
14+
two: {} as IThing<typeof bar>,
15+
}
16+
17+
let bar = {
18+
three: {} as IThing<typeof bar>,
19+
}
20+
21+
const qwe = {
22+
four: {} as IThing<typeof qwe>,
23+
}

0 commit comments

Comments
 (0)