-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Fix inferences between alias type arguments and defaulted alias type arguments #51771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eb8ed4f
978b474
9f806ef
c27fc75
9e8c50d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
} | ||
|
@@ -23698,8 +23702,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!; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I wasn't even aware that the type argument list could be incomplete at this point, and I'm not sure that was ever intended. It's fine for type arguments to be missing at the lexical level, but once we're dealing with types we pretty much assume that the length of a type argument list matches the length of the corresponding type parameter list. That assumption is pretty pervasive throughout the compiler (modulo the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, so, our old logic for giving an alias symbol instantiation an alias symbol didn't fill missing type arguments, which is why the new condition I added also didn't - it didn't seem required, since our existing usage didn't fill them. Obviously, broader usage of these unfilled lists reveals the flaw, namely inference (and probably comparison checking) not going well, since, as you said, they currently expect filled lists. Thing is, I think trafficking the unfilled lists has an advantage - it may be worth handling incomplete lists in inference/comparison checking. If we start filling them eagerly, rather than getting the user-supplied list, when we printback, we don't printback the user supplied list anymore. Meaning, even though you wrote |
||
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)); | ||
jakebailey marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
//// [tests/cases/compiler/importedAliasedConditionalTypeInstantiation.ts] //// | ||
|
||
//// [index.d.ts] | ||
export type Handler<TEvent = any, TResult = any> = ( | ||
event: TEvent, | ||
context: {}, | ||
callback: Callback<TResult>, | ||
) => void | Promise<TResult>; | ||
|
||
export type Callback<TResult = any> = (error?: Error | string | null, result?: TResult) => void; | ||
|
||
//// [index.d.ts] | ||
import { Handler, Callback } from 'aws-lambda'; | ||
declare namespace lambdaTester { | ||
type HandlerEvent<T extends Handler> = T extends Handler<infer TEvent> ? TEvent : never; | ||
type HandlerResult<T extends Handler> = T extends Handler<any, infer TResult> ? TResult : never; | ||
type HandlerError<T extends Handler> = T extends Handler<any, infer TResult> | ||
? NonNullable<Parameters<Callback<TResult>>['0']> | ||
: never; | ||
|
||
interface VerifierFn<S> { | ||
(result: S, additional?: any): void | Promise<void>; | ||
(result: S, additional?: any, done?: () => {}): void; | ||
} | ||
type Verifier<S> = S extends HandlerError<Handler> | ||
? S extends string | ||
? VerifierFn<string> | ||
: S extends Error | ||
? VerifierFn<Error> | ||
: never | ||
: VerifierFn<S>; | ||
|
||
class LambdaTester<T extends Handler> { | ||
event(event: HandlerEvent<T>): this; | ||
} | ||
} | ||
|
||
declare function lambdaTester<T extends Handler>(handler: T): lambdaTester.LambdaTester<T>; | ||
|
||
export = lambdaTester; | ||
//// [index.ts] | ||
import * as lambdaTester from 'lambda-tester'; | ||
import { Handler } from 'aws-lambda'; | ||
|
||
type Actual = lambdaTester.Verifier<lambdaTester.HandlerResult<Handler>>; | ||
type Expected = lambdaTester.Verifier<lambdaTester.HandlerResult<Handler<any, any>>>; | ||
|
||
//// [index.js] | ||
"use strict"; | ||
exports.__esModule = true; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
=== tests/cases/compiler/node_modules/aws-lambda/index.d.ts === | ||
export type Handler<TEvent = any, TResult = any> = ( | ||
>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<TResult>, | ||
>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<TResult>; | ||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) | ||
>TResult : Symbol(TResult, Decl(index.d.ts, 0, 33)) | ||
|
||
export type Callback<TResult = any> = (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> = T extends Handler<infer TEvent> ? 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> = T extends Handler<any, infer TResult> ? 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> = T extends Handler<any, infer TResult> | ||
>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<Parameters<Callback<TResult>>['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<S> { | ||
>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) | ||
>S : Symbol(S, Decl(index.d.ts, 8, 25)) | ||
|
||
(result: S, additional?: any): void | Promise<void>; | ||
>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> = S extends HandlerError<Handler> | ||
>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<string> | ||
>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<Error> | ||
>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) | ||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) | ||
|
||
: never | ||
: VerifierFn<S>; | ||
>VerifierFn : Symbol(VerifierFn, Decl(index.d.ts, 6, 16)) | ||
>S : Symbol(S, Decl(index.d.ts, 12, 18)) | ||
|
||
class LambdaTester<T extends Handler> { | ||
>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<T>): 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<T extends Handler>(handler: T): lambdaTester.LambdaTester<T>; | ||
>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<lambdaTester.HandlerResult<Handler>>; | ||
>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<lambdaTester.HandlerResult<Handler<any, any>>>; | ||
>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)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
=== tests/cases/compiler/node_modules/aws-lambda/index.d.ts === | ||
export type Handler<TEvent = any, TResult = any> = ( | ||
>Handler : Handler<TEvent, TResult> | ||
|
||
event: TEvent, | ||
>event : TEvent | ||
|
||
context: {}, | ||
>context : {} | ||
|
||
callback: Callback<TResult>, | ||
>callback : Callback<TResult> | ||
|
||
) => void | Promise<TResult>; | ||
|
||
export type Callback<TResult = any> = (error?: Error | string | null, result?: TResult) => void; | ||
>Callback : Callback<TResult> | ||
>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> = T extends Handler<infer TEvent> ? TEvent : never; | ||
>HandlerEvent : HandlerEvent<T> | ||
|
||
type HandlerResult<T extends Handler> = T extends Handler<any, infer TResult> ? TResult : never; | ||
>HandlerResult : HandlerResult<T> | ||
|
||
type HandlerError<T extends Handler> = T extends Handler<any, infer TResult> | ||
>HandlerError : HandlerError<T> | ||
|
||
? NonNullable<Parameters<Callback<TResult>>['0']> | ||
: never; | ||
|
||
interface VerifierFn<S> { | ||
(result: S, additional?: any): void | Promise<void>; | ||
>result : S | ||
>additional : any | ||
|
||
(result: S, additional?: any, done?: () => {}): void; | ||
>result : S | ||
>additional : any | ||
>done : () => {} | ||
} | ||
type Verifier<S> = S extends HandlerError<Handler> | ||
>Verifier : Verifier<S> | ||
|
||
? S extends string | ||
? VerifierFn<string> | ||
: S extends Error | ||
? VerifierFn<Error> | ||
: never | ||
: VerifierFn<S>; | ||
|
||
class LambdaTester<T extends Handler> { | ||
>LambdaTester : LambdaTester<T> | ||
|
||
event(event: HandlerEvent<T>): this; | ||
>event : (event: HandlerEvent<T>) => this | ||
>event : HandlerEvent<T> | ||
} | ||
} | ||
|
||
declare function lambdaTester<T extends Handler>(handler: T): lambdaTester.LambdaTester<T>; | ||
>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<lambdaTester.HandlerResult<Handler>>; | ||
>Actual : lambdaTester.VerifierFn<string> | lambdaTester.VerifierFn<Error> | lambdaTester.VerifierFn<any> | ||
>lambdaTester : any | ||
>lambdaTester : any | ||
|
||
type Expected = lambdaTester.Verifier<lambdaTester.HandlerResult<Handler<any, any>>>; | ||
>Expected : lambdaTester.VerifierFn<string> | lambdaTester.VerifierFn<Error> | lambdaTester.VerifierFn<any> | ||
>lambdaTester : any | ||
>lambdaTester : any | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// @filename: node_modules/aws-lambda/index.d.ts | ||
export type Handler<TEvent = any, TResult = any> = ( | ||
event: TEvent, | ||
context: {}, | ||
callback: Callback<TResult>, | ||
) => void | Promise<TResult>; | ||
|
||
export type Callback<TResult = any> = (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> = T extends Handler<infer TEvent> ? TEvent : never; | ||
type HandlerResult<T extends Handler> = T extends Handler<any, infer TResult> ? TResult : never; | ||
type HandlerError<T extends Handler> = T extends Handler<any, infer TResult> | ||
? NonNullable<Parameters<Callback<TResult>>['0']> | ||
: never; | ||
|
||
interface VerifierFn<S> { | ||
(result: S, additional?: any): void | Promise<void>; | ||
(result: S, additional?: any, done?: () => {}): void; | ||
} | ||
type Verifier<S> = S extends HandlerError<Handler> | ||
? S extends string | ||
? VerifierFn<string> | ||
: S extends Error | ||
? VerifierFn<Error> | ||
: never | ||
: VerifierFn<S>; | ||
|
||
class LambdaTester<T extends Handler> { | ||
event(event: HandlerEvent<T>): this; | ||
} | ||
} | ||
|
||
declare function lambdaTester<T extends Handler>(handler: T): lambdaTester.LambdaTester<T>; | ||
|
||
export = lambdaTester; | ||
// @filename: index.ts | ||
|
||
import * as lambdaTester from 'lambda-tester'; | ||
import { Handler } from 'aws-lambda'; | ||
|
||
type Actual = lambdaTester.Verifier<lambdaTester.HandlerResult<Handler>>; | ||
type Expected = lambdaTester.Verifier<lambdaTester.HandlerResult<Handler<any, any>>>; |
Uh oh!
There was an error while loading. Please reload this page.