Skip to content

Commit

Permalink
Fix inferences between alias type arguments and defaulted alias type …
Browse files Browse the repository at this point in the history
…arguments (#51771)
  • Loading branch information
weswigham authored Jan 11, 2023
1 parent 6860373 commit 9da2a9a
Show file tree
Hide file tree
Showing 5 changed files with 364 additions and 3 deletions.
14 changes: 11 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20871,7 +20871,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;
}
Expand Down Expand Up @@ -23805,8 +23809,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, 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.
return;
Expand Down
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>>>;

0 comments on commit 9da2a9a

Please sign in to comment.