Fixed a redundant used before defined error (#55283)

This commit is contained in:
Mateusz Burzyński 2023-08-24 17:35:48 +02:00 committed by GitHub
parent 769f2daf71
commit f07077c7ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 132 additions and 6 deletions

View File

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

View File

@ -0,0 +1,50 @@
//// [tests/cases/compiler/noUsedBeforeDefinedErrorInTypeContext.ts] ////
=== noUsedBeforeDefinedErrorInTypeContext.ts ===
// https://github.com/microsoft/TypeScript/issues/8775
interface IThing<T> {
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
>T : Symbol(T, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 17))
owner: T;
>owner : Symbol(IThing.owner, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 21))
>T : Symbol(T, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 2, 17))
}
var foo = {
>foo : Symbol(foo, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 3))
one: {} as IThing<typeof foo>,
>one : Symbol(one, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 11))
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
>foo : Symbol(foo, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 6, 3))
}
let baz = {
>baz : Symbol(baz, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 10, 3))
two: {} as IThing<typeof bar>,
>two : Symbol(two, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 10, 11))
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
}
let bar = {
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
three: {} as IThing<typeof bar>,
>three : Symbol(three, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 11))
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
>bar : Symbol(bar, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 14, 3))
}
const qwe = {
>qwe : Symbol(qwe, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 5))
four: {} as IThing<typeof qwe>,
>four : Symbol(four, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 13))
>IThing : Symbol(IThing, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 0, 0))
>qwe : Symbol(qwe, Decl(noUsedBeforeDefinedErrorInTypeContext.ts, 18, 5))
}

View File

@ -0,0 +1,54 @@
//// [tests/cases/compiler/noUsedBeforeDefinedErrorInTypeContext.ts] ////
=== noUsedBeforeDefinedErrorInTypeContext.ts ===
// https://github.com/microsoft/TypeScript/issues/8775
interface IThing<T> {
owner: T;
>owner : T
}
var foo = {
>foo : any
>{ one: {} as IThing<typeof foo>,} : { one: IThing<any>; }
one: {} as IThing<typeof foo>,
>one : IThing<any>
>{} as IThing<typeof foo> : IThing<any>
>{} : {}
>foo : any
}
let baz = {
>baz : { two: IThing<any>; }
>{ two: {} as IThing<typeof bar>,} : { two: IThing<any>; }
two: {} as IThing<typeof bar>,
>two : IThing<any>
>{} as IThing<typeof bar> : IThing<any>
>{} : {}
>bar : any
}
let bar = {
>bar : any
>{ three: {} as IThing<typeof bar>,} : { three: IThing<any>; }
three: {} as IThing<typeof bar>,
>three : IThing<any>
>{} as IThing<typeof bar> : IThing<any>
>{} : {}
>bar : any
}
const qwe = {
>qwe : any
>{ four: {} as IThing<typeof qwe>,} : { four: IThing<any>; }
four: {} as IThing<typeof qwe>,
>four : IThing<any>
>{} as IThing<typeof qwe> : IThing<any>
>{} : {}
>qwe : any
}

View File

@ -0,0 +1,23 @@
// @noEmit: true
// https://github.com/microsoft/TypeScript/issues/8775
interface IThing<T> {
owner: T;
}
var foo = {
one: {} as IThing<typeof foo>,
}
let baz = {
two: {} as IThing<typeof bar>,
}
let bar = {
three: {} as IThing<typeof bar>,
}
const qwe = {
four: {} as IThing<typeof qwe>,
}