From eb8ed4f314966d510a5795e5dfc610c8abde7680 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 5 Dec 2022 15:19:34 -0800 Subject: [PATCH 1/5] Fix inferences between alias type arguments and defaulted alias type arguments --- src/compiler/checker.ts | 7 +- ...rtedAliasedConditionalTypeInstantiation.js | 50 ++++++ ...liasedConditionalTypeInstantiation.symbols | 163 ++++++++++++++++++ ...dAliasedConditionalTypeInstantiation.types | 95 ++++++++++ ...rtedAliasedConditionalTypeInstantiation.ts | 45 +++++ 5 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/importedAliasedConditionalTypeInstantiation.js create mode 100644 tests/baselines/reference/importedAliasedConditionalTypeInstantiation.symbols create mode 100644 tests/baselines/reference/importedAliasedConditionalTypeInstantiation.types create mode 100644 tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 69a8c4272608c..2284e1d742143 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23698,8 +23698,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { if (source.aliasTypeArguments) { // Source and target are types originating in the same generic type alias declaration. - // Simply infer from source type arguments to target type arguments. - inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); + // Simply infer from source type arguments to target type arguments, with defaults applied. + const params = getSymbolLinks(source.aliasSymbol).typeParameters!; + const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, getMinTypeArgumentCount(params), /*isJs*/ false); + const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, getMinTypeArgumentCount(params), /*isJs*/ false); + inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; diff --git a/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.js b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.js new file mode 100644 index 0000000000000..6cdcc54d98189 --- /dev/null +++ b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.js @@ -0,0 +1,50 @@ +//// [tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts] //// + +//// [index.d.ts] +export type Handler = ( + event: TEvent, + context: {}, + callback: Callback, +) => void | Promise; + +export type Callback = (error?: Error | string | null, result?: TResult) => void; + +//// [index.d.ts] +import { Handler, Callback } from 'aws-lambda'; +declare namespace lambdaTester { + type HandlerEvent = T extends Handler ? TEvent : never; + type HandlerResult = T extends Handler ? TResult : never; + type HandlerError = T extends Handler + ? NonNullable>['0']> + : never; + + interface VerifierFn { + (result: S, additional?: any): void | Promise; + (result: S, additional?: any, done?: () => {}): void; + } + type Verifier = S extends HandlerError + ? S extends string + ? VerifierFn + : S extends Error + ? VerifierFn + : never + : VerifierFn; + + class LambdaTester { + event(event: HandlerEvent): this; + } +} + +declare function lambdaTester(handler: T): lambdaTester.LambdaTester; + +export = lambdaTester; +//// [index.ts] +import * as lambdaTester from 'lambda-tester'; +import { Handler } from 'aws-lambda'; + +type Actual = lambdaTester.Verifier>; +type Expected = lambdaTester.Verifier>>; + +//// [index.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.symbols b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.symbols new file mode 100644 index 0000000000000..8e2b87d235d40 --- /dev/null +++ b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.symbols @@ -0,0 +1,163 @@ +=== tests/cases/compiler/node_modules/aws-lambda/index.d.ts === +export type Handler = ( +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 0)) +>TEvent : Symbol(TEvent, Decl(index.d.ts, 0, 20)) +>TResult : Symbol(TResult, Decl(index.d.ts, 0, 33)) + + event: TEvent, +>event : Symbol(event, Decl(index.d.ts, 0, 52)) +>TEvent : Symbol(TEvent, Decl(index.d.ts, 0, 20)) + + context: {}, +>context : Symbol(context, Decl(index.d.ts, 1, 18)) + + callback: Callback, +>callback : Symbol(callback, Decl(index.d.ts, 2, 16)) +>Callback : Symbol(Callback, Decl(index.d.ts, 4, 29)) +>TResult : Symbol(TResult, Decl(index.d.ts, 0, 33)) + +) => void | Promise; +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>TResult : Symbol(TResult, Decl(index.d.ts, 0, 33)) + +export type Callback = (error?: Error | string | null, result?: TResult) => void; +>Callback : Symbol(Callback, Decl(index.d.ts, 4, 29)) +>TResult : Symbol(TResult, Decl(index.d.ts, 6, 21)) +>error : Symbol(error, Decl(index.d.ts, 6, 39)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(index.d.ts, 6, 69)) +>TResult : Symbol(TResult, Decl(index.d.ts, 6, 21)) + +=== tests/cases/compiler/node_modules/lambda-tester/index.d.ts === +import { Handler, Callback } from 'aws-lambda'; +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>Callback : Symbol(Callback, Decl(index.d.ts, 0, 17)) + +declare namespace lambdaTester { +>lambdaTester : Symbol(lambdaTester, Decl(index.d.ts, 23, 1), Decl(index.d.ts, 0, 47)) + + type HandlerEvent = T extends Handler ? TEvent : never; +>HandlerEvent : Symbol(HandlerEvent, Decl(index.d.ts, 1, 32)) +>T : Symbol(T, Decl(index.d.ts, 2, 22)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>T : Symbol(T, Decl(index.d.ts, 2, 22)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>TEvent : Symbol(TEvent, Decl(index.d.ts, 2, 66)) +>TEvent : Symbol(TEvent, Decl(index.d.ts, 2, 66)) + + type HandlerResult = T extends Handler ? TResult : never; +>HandlerResult : Symbol(HandlerResult, Decl(index.d.ts, 2, 92)) +>T : Symbol(T, Decl(index.d.ts, 3, 23)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>T : Symbol(T, Decl(index.d.ts, 3, 23)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>TResult : Symbol(TResult, Decl(index.d.ts, 3, 72)) +>TResult : Symbol(TResult, Decl(index.d.ts, 3, 72)) + + type HandlerError = T extends Handler +>HandlerError : Symbol(HandlerError, Decl(index.d.ts, 3, 100)) +>T : Symbol(T, Decl(index.d.ts, 4, 22)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>T : Symbol(T, Decl(index.d.ts, 4, 22)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>TResult : Symbol(TResult, Decl(index.d.ts, 4, 71)) + + ? NonNullable>['0']> +>NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>Callback : Symbol(Callback, Decl(index.d.ts, 0, 17)) +>TResult : Symbol(TResult, Decl(index.d.ts, 4, 71)) + + : never; + + interface VerifierFn { +>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) +>S : Symbol(S, Decl(index.d.ts, 8, 25)) + + (result: S, additional?: any): void | Promise; +>result : Symbol(result, Decl(index.d.ts, 9, 9)) +>S : Symbol(S, Decl(index.d.ts, 8, 25)) +>additional : Symbol(additional, Decl(index.d.ts, 9, 19)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + + (result: S, additional?: any, done?: () => {}): void; +>result : Symbol(result, Decl(index.d.ts, 10, 9)) +>S : Symbol(S, Decl(index.d.ts, 8, 25)) +>additional : Symbol(additional, Decl(index.d.ts, 10, 19)) +>done : Symbol(done, Decl(index.d.ts, 10, 37)) + } + type Verifier = S extends HandlerError +>Verifier : Symbol(Verifier, Decl(index.d.ts, 11, 5)) +>S : Symbol(S, Decl(index.d.ts, 12, 18)) +>S : Symbol(S, Decl(index.d.ts, 12, 18)) +>HandlerError : Symbol(HandlerError, Decl(index.d.ts, 3, 100)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) + + ? S extends string +>S : Symbol(S, Decl(index.d.ts, 12, 18)) + + ? VerifierFn +>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) + + : S extends Error +>S : Symbol(S, Decl(index.d.ts, 12, 18)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + ? VerifierFn +>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + : never + : VerifierFn; +>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) +>S : Symbol(S, Decl(index.d.ts, 12, 18)) + + class LambdaTester { +>LambdaTester : Symbol(LambdaTester, Decl(index.d.ts, 18, 24)) +>T : Symbol(T, Decl(index.d.ts, 20, 23)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) + + event(event: HandlerEvent): this; +>event : Symbol(LambdaTester.event, Decl(index.d.ts, 20, 43)) +>event : Symbol(event, Decl(index.d.ts, 21, 14)) +>HandlerEvent : Symbol(HandlerEvent, Decl(index.d.ts, 1, 32)) +>T : Symbol(T, Decl(index.d.ts, 20, 23)) + } +} + +declare function lambdaTester(handler: T): lambdaTester.LambdaTester; +>lambdaTester : Symbol(lambdaTester, Decl(index.d.ts, 23, 1), Decl(index.d.ts, 0, 47)) +>T : Symbol(T, Decl(index.d.ts, 25, 30)) +>Handler : Symbol(Handler, Decl(index.d.ts, 0, 8)) +>handler : Symbol(handler, Decl(index.d.ts, 25, 49)) +>T : Symbol(T, Decl(index.d.ts, 25, 30)) +>lambdaTester : Symbol(lambdaTester, Decl(index.d.ts, 23, 1), Decl(index.d.ts, 0, 47)) +>LambdaTester : Symbol(lambdaTester.LambdaTester, Decl(index.d.ts, 18, 24)) +>T : Symbol(T, Decl(index.d.ts, 25, 30)) + +export = lambdaTester; +>lambdaTester : Symbol(lambdaTester, Decl(index.d.ts, 23, 1), Decl(index.d.ts, 0, 47)) + +=== tests/cases/compiler/index.ts === +import * as lambdaTester from 'lambda-tester'; +>lambdaTester : Symbol(lambdaTester, Decl(index.ts, 0, 6)) + +import { Handler } from 'aws-lambda'; +>Handler : Symbol(Handler, Decl(index.ts, 1, 8)) + +type Actual = lambdaTester.Verifier>; +>Actual : Symbol(Actual, Decl(index.ts, 1, 37)) +>lambdaTester : Symbol(lambdaTester, Decl(index.ts, 0, 6)) +>Verifier : Symbol(lambdaTester.Verifier, Decl(index.d.ts, 11, 5)) +>lambdaTester : Symbol(lambdaTester, Decl(index.ts, 0, 6)) +>HandlerResult : Symbol(lambdaTester.HandlerResult, Decl(index.d.ts, 2, 92)) +>Handler : Symbol(Handler, Decl(index.ts, 1, 8)) + +type Expected = lambdaTester.Verifier>>; +>Expected : Symbol(Expected, Decl(index.ts, 3, 73)) +>lambdaTester : Symbol(lambdaTester, Decl(index.ts, 0, 6)) +>Verifier : Symbol(lambdaTester.Verifier, Decl(index.d.ts, 11, 5)) +>lambdaTester : Symbol(lambdaTester, Decl(index.ts, 0, 6)) +>HandlerResult : Symbol(lambdaTester.HandlerResult, Decl(index.d.ts, 2, 92)) +>Handler : Symbol(Handler, Decl(index.ts, 1, 8)) + diff --git a/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.types b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.types new file mode 100644 index 0000000000000..968fc10d0b597 --- /dev/null +++ b/tests/baselines/reference/importedAliasedConditionalTypeInstantiation.types @@ -0,0 +1,95 @@ +=== tests/cases/compiler/node_modules/aws-lambda/index.d.ts === +export type Handler = ( +>Handler : Handler + + event: TEvent, +>event : TEvent + + context: {}, +>context : {} + + callback: Callback, +>callback : Callback + +) => void | Promise; + +export type Callback = (error?: Error | string | null, result?: TResult) => void; +>Callback : Callback +>error : string | Error +>null : null +>result : TResult + +=== tests/cases/compiler/node_modules/lambda-tester/index.d.ts === +import { Handler, Callback } from 'aws-lambda'; +>Handler : any +>Callback : any + +declare namespace lambdaTester { +>lambdaTester : typeof lambdaTester + + type HandlerEvent = T extends Handler ? TEvent : never; +>HandlerEvent : HandlerEvent + + type HandlerResult = T extends Handler ? TResult : never; +>HandlerResult : HandlerResult + + type HandlerError = T extends Handler +>HandlerError : HandlerError + + ? NonNullable>['0']> + : never; + + interface VerifierFn { + (result: S, additional?: any): void | Promise; +>result : S +>additional : any + + (result: S, additional?: any, done?: () => {}): void; +>result : S +>additional : any +>done : () => {} + } + type Verifier = S extends HandlerError +>Verifier : Verifier + + ? S extends string + ? VerifierFn + : S extends Error + ? VerifierFn + : never + : VerifierFn; + + class LambdaTester { +>LambdaTester : LambdaTester + + event(event: HandlerEvent): this; +>event : (event: HandlerEvent) => this +>event : HandlerEvent + } +} + +declare function lambdaTester(handler: T): lambdaTester.LambdaTester; +>lambdaTester : typeof lambdaTester +>handler : T +>lambdaTester : any + +export = lambdaTester; +>lambdaTester : typeof lambdaTester + +=== tests/cases/compiler/index.ts === +import * as lambdaTester from 'lambda-tester'; +>lambdaTester : typeof lambdaTester + +import { Handler } from 'aws-lambda'; +>Handler : any + +type Actual = lambdaTester.Verifier>; +>Actual : lambdaTester.VerifierFn | lambdaTester.VerifierFn | lambdaTester.VerifierFn +>lambdaTester : any +>lambdaTester : any + +type Expected = lambdaTester.Verifier>>; +>Expected : lambdaTester.VerifierFn | lambdaTester.VerifierFn | lambdaTester.VerifierFn +>lambdaTester : any +>lambdaTester : any + diff --git a/tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts b/tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts new file mode 100644 index 0000000000000..96db52728c46f --- /dev/null +++ b/tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts @@ -0,0 +1,45 @@ +// @filename: node_modules/aws-lambda/index.d.ts +export type Handler = ( + event: TEvent, + context: {}, + callback: Callback, +) => void | Promise; + +export type Callback = (error?: Error | string | null, result?: TResult) => void; + +// @filename: node_modules/lambda-tester/index.d.ts +import { Handler, Callback } from 'aws-lambda'; +declare namespace lambdaTester { + type HandlerEvent = T extends Handler ? TEvent : never; + type HandlerResult = T extends Handler ? TResult : never; + type HandlerError = T extends Handler + ? NonNullable>['0']> + : never; + + interface VerifierFn { + (result: S, additional?: any): void | Promise; + (result: S, additional?: any, done?: () => {}): void; + } + type Verifier = S extends HandlerError + ? S extends string + ? VerifierFn + : S extends Error + ? VerifierFn + : never + : VerifierFn; + + class LambdaTester { + event(event: HandlerEvent): this; + } +} + +declare function lambdaTester(handler: T): lambdaTester.LambdaTester; + +export = lambdaTester; +// @filename: index.ts + +import * as lambdaTester from 'lambda-tester'; +import { Handler } from 'aws-lambda'; + +type Actual = lambdaTester.Verifier>; +type Expected = lambdaTester.Verifier>>; \ No newline at end of file From 978b47497e0505328ffc4b4cd31cddc676f632f9 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 5 Dec 2022 15:24:33 -0800 Subject: [PATCH 2/5] Extract value --- src/compiler/checker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2284e1d742143..86893660ce6cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23700,8 +23700,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Source and target are types originating in the same generic type alias declaration. // Simply infer from source type arguments to target type arguments, with defaults applied. const params = getSymbolLinks(source.aliasSymbol).typeParameters!; - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, getMinTypeArgumentCount(params), /*isJs*/ false); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, getMinTypeArgumentCount(params), /*isJs*/ false); + const minParams = getMinTypeArgumentCount(params); + const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, /*isJs*/ false); + const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, /*isJs*/ false); inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. From 9f806ef497a9c63fc9e5cc7084416d24e5ca8bb8 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 8 Dec 2022 14:08:14 -0800 Subject: [PATCH 3/5] Ensure type parameter lists are filled at each callsite, rather than within inference --- src/compiler/checker.ts | 12 ++++-------- ...AssignedNamespaceNoTripleSlashTypesReference.js | 2 +- ...ignedNamespaceNoTripleSlashTypesReference.types | 14 +++++++------- .../fixCrashAliasLookupForDefauledImport.types | 4 ++-- ...ericInferenceDefaultTypeParameterJsxReact.types | 4 ++-- .../reference/jsDeclarationsReactComponents.types | 12 ++++++------ .../reference/ramdaToolsNoInfinite2.types | 10 +++++----- 7 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 86893660ce6cd..eceaf73bc60c8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14896,11 +14896,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const resolved = resolveAlias(aliasSymbol); if (resolved && resolved.flags & SymbolFlags.TypeAlias) { newAliasSymbol = resolved; - aliasTypeArguments = typeArgumentsFromTypeReferenceNode(node) || (typeParameters ? [] : undefined); + aliasTypeArguments = typeParameters ? fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isInJSFile(node)) : undefined; } } } - return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, aliasTypeArguments); + return getTypeAliasInstantiation(symbol, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isInJSFile(node)), newAliasSymbol, aliasTypeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -23698,12 +23698,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { if (source.aliasTypeArguments) { // Source and target are types originating in the same generic type alias declaration. - // Simply infer from source type arguments to target type arguments, with defaults applied. - const params = getSymbolLinks(source.aliasSymbol).typeParameters!; - const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, /*isJs*/ false); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, /*isJs*/ false); - inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); + // Simply infer from source type arguments to target type arguments + inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; diff --git a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js index 9892c1d7a40e2..6e3ba8f5d7649 100644 --- a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js +++ b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js @@ -80,7 +80,7 @@ import { Component } from 'react'; export declare function getComp(): Component; //// [inferred-comp-export.d.ts] export declare const obj: { - comp: import("react").Component; + comp: import("react").Component; }; //// [some-other-file.d.ts] export * from '@emotion/core'; diff --git a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types index 2468381ef98b4..77105a8482e1f 100644 --- a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types +++ b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types @@ -36,24 +36,24 @@ export function getComp(): Component { >getComp : () => Component return {} as any as Component ->{} as any as Component : Component +>{} as any as Component : Component >{} as any : any >{} : {} } === tests/cases/compiler/src/inferred-comp-export.ts === import { getComp } from "./get-comp"; ->getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component // this shouldn't need any triple-slash references - it should have a direct import to `react` and that's it // This issue (#35343) _only_ reproduces in the test harness when the file in question is in a subfolder export const obj = { ->obj : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } ->{ comp: getComp()} : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } +>obj : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } +>{ comp: getComp()} : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } comp: getComp() ->comp : import("tests/cases/compiler/node_modules/@types/react/index").Component ->getComp() : import("tests/cases/compiler/node_modules/@types/react/index").Component ->getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component +>comp : import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp() : import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component } === tests/cases/compiler/src/some-other-file.ts === diff --git a/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types b/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types index 6842c50459cc9..38cdf50d333ed 100644 --- a/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types +++ b/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types @@ -8,7 +8,7 @@ import {Foo} from "./input"; function bar(element: Foo) { >bar : (element: Foo) => number ->element : Foo +>element : Foo return 1; >1 : 1 @@ -16,7 +16,7 @@ function bar(element: Foo) { bar(1 as Foo); >bar(1 as Foo) : number ->bar : (element: Foo) => number +>bar : (element: Foo) => number >1 as Foo : Foo >1 : 1 diff --git a/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types b/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types index 2033cf386b860..357408d93bdde 100644 --- a/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types +++ b/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types @@ -14,7 +14,7 @@ type ButtonBaseProps = ComponentPropsWithRef & { child >children : React.ReactNode function Component(props: ButtonBaseProps) { ->Component : (props: ButtonBaseProps) => JSX.Element +>Component : = "span">(props: ButtonBaseProps) => JSX.Element >props : ButtonBaseProps return <>; @@ -24,7 +24,7 @@ function Component(props: ButtonBaseProps) { const v1 = e.preventDefault()} />; >v1 : JSX.Element > e.preventDefault()} /> : JSX.Element ->Component : (props: ButtonBaseProps) => JSX.Element +>Component : = "span">(props: ButtonBaseProps) => JSX.Element >onClick : (e: React.MouseEvent) => void >e => e.preventDefault() : (e: React.MouseEvent) => void >e : React.MouseEvent diff --git a/tests/baselines/reference/jsDeclarationsReactComponents.types b/tests/baselines/reference/jsDeclarationsReactComponents.types index 4934a173b935b..bbf0a85737499 100644 --- a/tests/baselines/reference/jsDeclarationsReactComponents.types +++ b/tests/baselines/reference/jsDeclarationsReactComponents.types @@ -60,8 +60,8 @@ import React from "react"; * @type {React.SFC} */ const TabbedShowLayout = () => { ->TabbedShowLayout : React.SFC<{}> ->() => { return (
ok
);} : { (): JSX.Element; defaultProps: Partial<{}> | undefined; } +>TabbedShowLayout : React.SFC +>() => { return (
ok
);} : { (): JSX.Element; defaultProps: Partial | undefined; } return ( >(
ok
) : JSX.Element @@ -81,9 +81,9 @@ const TabbedShowLayout = () => { TabbedShowLayout.defaultProps = { >TabbedShowLayout.defaultProps = { tabs: "default value"} : { tabs: string; } ->TabbedShowLayout.defaultProps : Partial<{}> | undefined ->TabbedShowLayout : React.SFC<{}> ->defaultProps : Partial<{}> | undefined +>TabbedShowLayout.defaultProps : Partial | undefined +>TabbedShowLayout : React.SFC +>defaultProps : Partial | undefined >{ tabs: "default value"} : { tabs: string; } tabs: "default value" @@ -93,7 +93,7 @@ TabbedShowLayout.defaultProps = { }; export default TabbedShowLayout; ->TabbedShowLayout : React.SFC<{}> +>TabbedShowLayout : React.SFC === tests/cases/conformance/jsdoc/declarations/jsDeclarationsReactComponents3.jsx === import React from "react"; diff --git a/tests/baselines/reference/ramdaToolsNoInfinite2.types b/tests/baselines/reference/ramdaToolsNoInfinite2.types index 0c3850366aef5..47d6ff227da9b 100644 --- a/tests/baselines/reference/ramdaToolsNoInfinite2.types +++ b/tests/baselines/reference/ramdaToolsNoInfinite2.types @@ -1211,7 +1211,7 @@ declare module "List/NonNullable" { >NonNullable : NonNullable 1: Cast, List>; ->1 : Cast, List> +>1 : Cast, List> 0: ListOf, NumberOf, depth>>; >0 : ListOf, NumberOf, depth>> @@ -1329,7 +1329,7 @@ declare module "Function/Curry" { >0 : _GapsOf, Next> 1: _Concat>>; ->1 : _Concat>> +>1 : _Concat, "->">> }[Extends, Length>]; @@ -1345,9 +1345,9 @@ declare module "Function/Curry" { export type Curry = (...args: Cast>>) => GapsOf> extends infer G ? Length> extends infer L ? L extends 0 ? Return : L extends 1 ? Curry<(...args: Cast) => Return> & ((...args: Cast) => Return) : Curry<(...args: Cast) => Return> : never : never; >Curry : Curry >args : Cast>> ->args : Cast ->args : Cast ->args : Cast +>args : Cast> +>args : Cast> +>args : Cast> } From c27fc75e64d25908ec310fcaaa5a3d0ae566dd37 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 8 Dec 2022 14:28:08 -0800 Subject: [PATCH 4/5] Revert "Ensure type parameter lists are filled at each callsite, rather than within inference" This reverts commit 9f806ef497a9c63fc9e5cc7084416d24e5ca8bb8. --- src/compiler/checker.ts | 12 ++++++++---- ...AssignedNamespaceNoTripleSlashTypesReference.js | 2 +- ...ignedNamespaceNoTripleSlashTypesReference.types | 14 +++++++------- .../fixCrashAliasLookupForDefauledImport.types | 4 ++-- ...ericInferenceDefaultTypeParameterJsxReact.types | 4 ++-- .../reference/jsDeclarationsReactComponents.types | 12 ++++++------ .../reference/ramdaToolsNoInfinite2.types | 10 +++++----- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index eceaf73bc60c8..86893660ce6cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14896,11 +14896,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const resolved = resolveAlias(aliasSymbol); if (resolved && resolved.flags & SymbolFlags.TypeAlias) { newAliasSymbol = resolved; - aliasTypeArguments = typeParameters ? fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isInJSFile(node)) : undefined; + aliasTypeArguments = typeArgumentsFromTypeReferenceNode(node) || (typeParameters ? [] : undefined); } } } - return getTypeAliasInstantiation(symbol, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isInJSFile(node)), newAliasSymbol, aliasTypeArguments); + return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node), newAliasSymbol, aliasTypeArguments); } return checkNoTypeArguments(node, symbol) ? type : errorType; } @@ -23698,8 +23698,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (source.aliasSymbol && source.aliasSymbol === target.aliasSymbol) { if (source.aliasTypeArguments) { // Source and target are types originating in the same generic type alias declaration. - // Simply infer from source type arguments to target type arguments - inferFromTypeArguments(source.aliasTypeArguments, target.aliasTypeArguments!, getAliasVariances(source.aliasSymbol)); + // Simply infer from source type arguments to target type arguments, with defaults applied. + const params = getSymbolLinks(source.aliasSymbol).typeParameters!; + const minParams = getMinTypeArgumentCount(params); + const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, /*isJs*/ false); + const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, /*isJs*/ false); + inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same. return; diff --git a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js index 6e3ba8f5d7649..9892c1d7a40e2 100644 --- a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js +++ b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.js @@ -80,7 +80,7 @@ import { Component } from 'react'; export declare function getComp(): Component; //// [inferred-comp-export.d.ts] export declare const obj: { - comp: import("react").Component; + comp: import("react").Component; }; //// [some-other-file.d.ts] export * from '@emotion/core'; diff --git a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types index 77105a8482e1f..2468381ef98b4 100644 --- a/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types +++ b/tests/baselines/reference/declarationEmitExportAssignedNamespaceNoTripleSlashTypesReference.types @@ -36,24 +36,24 @@ export function getComp(): Component { >getComp : () => Component return {} as any as Component ->{} as any as Component : Component +>{} as any as Component : Component >{} as any : any >{} : {} } === tests/cases/compiler/src/inferred-comp-export.ts === import { getComp } from "./get-comp"; ->getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component // this shouldn't need any triple-slash references - it should have a direct import to `react` and that's it // This issue (#35343) _only_ reproduces in the test harness when the file in question is in a subfolder export const obj = { ->obj : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } ->{ comp: getComp()} : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } +>obj : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } +>{ comp: getComp()} : { comp: import("tests/cases/compiler/node_modules/@types/react/index").Component; } comp: getComp() ->comp : import("tests/cases/compiler/node_modules/@types/react/index").Component ->getComp() : import("tests/cases/compiler/node_modules/@types/react/index").Component ->getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component +>comp : import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp() : import("tests/cases/compiler/node_modules/@types/react/index").Component +>getComp : () => import("tests/cases/compiler/node_modules/@types/react/index").Component } === tests/cases/compiler/src/some-other-file.ts === diff --git a/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types b/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types index 38cdf50d333ed..6842c50459cc9 100644 --- a/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types +++ b/tests/baselines/reference/fixCrashAliasLookupForDefauledImport.types @@ -8,7 +8,7 @@ import {Foo} from "./input"; function bar(element: Foo) { >bar : (element: Foo) => number ->element : Foo +>element : Foo return 1; >1 : 1 @@ -16,7 +16,7 @@ function bar(element: Foo) { bar(1 as Foo); >bar(1 as Foo) : number ->bar : (element: Foo) => number +>bar : (element: Foo) => number >1 as Foo : Foo >1 : 1 diff --git a/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types b/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types index 357408d93bdde..2033cf386b860 100644 --- a/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types +++ b/tests/baselines/reference/genericInferenceDefaultTypeParameterJsxReact.types @@ -14,7 +14,7 @@ type ButtonBaseProps = ComponentPropsWithRef & { child >children : React.ReactNode function Component(props: ButtonBaseProps) { ->Component : = "span">(props: ButtonBaseProps) => JSX.Element +>Component : (props: ButtonBaseProps) => JSX.Element >props : ButtonBaseProps return <>; @@ -24,7 +24,7 @@ function Component(props: ButtonBaseProps) { const v1 = e.preventDefault()} />; >v1 : JSX.Element > e.preventDefault()} /> : JSX.Element ->Component : = "span">(props: ButtonBaseProps) => JSX.Element +>Component : (props: ButtonBaseProps) => JSX.Element >onClick : (e: React.MouseEvent) => void >e => e.preventDefault() : (e: React.MouseEvent) => void >e : React.MouseEvent diff --git a/tests/baselines/reference/jsDeclarationsReactComponents.types b/tests/baselines/reference/jsDeclarationsReactComponents.types index bbf0a85737499..4934a173b935b 100644 --- a/tests/baselines/reference/jsDeclarationsReactComponents.types +++ b/tests/baselines/reference/jsDeclarationsReactComponents.types @@ -60,8 +60,8 @@ import React from "react"; * @type {React.SFC} */ const TabbedShowLayout = () => { ->TabbedShowLayout : React.SFC ->() => { return (
ok
);} : { (): JSX.Element; defaultProps: Partial | undefined; } +>TabbedShowLayout : React.SFC<{}> +>() => { return (
ok
);} : { (): JSX.Element; defaultProps: Partial<{}> | undefined; } return ( >(
ok
) : JSX.Element @@ -81,9 +81,9 @@ const TabbedShowLayout = () => { TabbedShowLayout.defaultProps = { >TabbedShowLayout.defaultProps = { tabs: "default value"} : { tabs: string; } ->TabbedShowLayout.defaultProps : Partial | undefined ->TabbedShowLayout : React.SFC ->defaultProps : Partial | undefined +>TabbedShowLayout.defaultProps : Partial<{}> | undefined +>TabbedShowLayout : React.SFC<{}> +>defaultProps : Partial<{}> | undefined >{ tabs: "default value"} : { tabs: string; } tabs: "default value" @@ -93,7 +93,7 @@ TabbedShowLayout.defaultProps = { }; export default TabbedShowLayout; ->TabbedShowLayout : React.SFC +>TabbedShowLayout : React.SFC<{}> === tests/cases/conformance/jsdoc/declarations/jsDeclarationsReactComponents3.jsx === import React from "react"; diff --git a/tests/baselines/reference/ramdaToolsNoInfinite2.types b/tests/baselines/reference/ramdaToolsNoInfinite2.types index 47d6ff227da9b..0c3850366aef5 100644 --- a/tests/baselines/reference/ramdaToolsNoInfinite2.types +++ b/tests/baselines/reference/ramdaToolsNoInfinite2.types @@ -1211,7 +1211,7 @@ declare module "List/NonNullable" { >NonNullable : NonNullable 1: Cast, List>; ->1 : Cast, List> +>1 : Cast, List> 0: ListOf, NumberOf, depth>>; >0 : ListOf, NumberOf, depth>> @@ -1329,7 +1329,7 @@ declare module "Function/Curry" { >0 : _GapsOf, Next> 1: _Concat>>; ->1 : _Concat, "->">> +>1 : _Concat>> }[Extends, Length>]; @@ -1345,9 +1345,9 @@ declare module "Function/Curry" { export type Curry = (...args: Cast>>) => GapsOf> extends infer G ? Length> extends infer L ? L extends 0 ? Return : L extends 1 ? Curry<(...args: Cast) => Return> & ((...args: Cast) => Return) : Curry<(...args: Cast) => Return> : never : never; >Curry : Curry >args : Cast>> ->args : Cast> ->args : Cast> ->args : Cast> +>args : Cast +>args : Cast +>args : Cast } From 9e8c50d22bc877d51cded1f2bd8f4dda37ae08a1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 8 Dec 2022 14:43:01 -0800 Subject: [PATCH 5/5] Ensure incomplete alias type argument lists are handled across the checker --- src/compiler/checker.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 86893660ce6cd..a3fc6ed3aa2ef 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20763,7 +20763,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (variances === emptyArray) { return Ternary.Unknown; } - const varianceResult = relateVariances(source.aliasTypeArguments, target.aliasTypeArguments, variances, intersectionState); + const params = getSymbolLinks(source.aliasSymbol).typeParameters!; + const minParams = getMinTypeArgumentCount(params); + const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); + const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); + const varianceResult = relateVariances(sourceTypes, targetTypes, variances, intersectionState); if (varianceResult !== undefined) { return varianceResult; } @@ -23701,8 +23705,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Simply infer from source type arguments to target type arguments, with defaults applied. const params = getSymbolLinks(source.aliasSymbol).typeParameters!; const minParams = getMinTypeArgumentCount(params); - const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, /*isJs*/ false); - const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, /*isJs*/ false); + const sourceTypes = fillMissingTypeArguments(source.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); + const targetTypes = fillMissingTypeArguments(target.aliasTypeArguments, params, minParams, isInJSFile(source.aliasSymbol.valueDeclaration)); inferFromTypeArguments(sourceTypes, targetTypes!, getAliasVariances(source.aliasSymbol)); } // And if there weren't any type arguments, there's no reason to run inference as the types must be the same.