From 949daeed7b3fa2dbd6925fed893b8d947b5982a2 Mon Sep 17 00:00:00 2001 From: Wesley Wigham <wewigham@microsoft.com> Date: Fri, 4 Mar 2022 13:44:05 -0800 Subject: [PATCH] Use strict variance checks for strict subtype checks unconditionally --- src/compiler/checker.ts | 13 ++- ...ayLiteralWithMultipleBestCommonTypes.types | 4 +- .../reference/arrayOfFunctionTypes3.types | 14 +-- .../reference/bestChoiceType.symbols | 18 +-- .../baselines/reference/bestChoiceType.types | 74 ++++++------- .../contextualTypingArrayOfLambdas.types | 4 +- .../flatArrayNoExcessiveStackDepth.types | 6 +- ...tializedDestructuringAssignmentTypes.types | 2 +- .../reference/strictSubtypeReduction.js | 61 +++++++++++ .../reference/strictSubtypeReduction.symbols | 99 +++++++++++++++++ .../reference/strictSubtypeReduction.types | 103 ++++++++++++++++++ ...trictSubtypeReductionStrictMode.errors.txt | 79 ++++++++++++++ .../strictSubtypeReductionStrictMode.js | 62 +++++++++++ .../strictSubtypeReductionStrictMode.symbols | 99 +++++++++++++++++ .../strictSubtypeReductionStrictMode.types | 103 ++++++++++++++++++ .../subtypingWithCallSignatures3.types | 16 +-- .../subtypingWithConstructSignatures3.types | 16 +-- .../reference/tsxUnionElementType3.errors.txt | 12 +- .../reference/tsxUnionElementType3.types | 8 +- .../reference/tsxUnionElementType4.errors.txt | 7 +- .../reference/tsxUnionElementType4.types | 6 +- .../cases/compiler/strictSubtypeReduction.ts | 32 ++++++ .../strictSubtypeReductionStrictMode.ts | 33 ++++++ 23 files changed, 770 insertions(+), 101 deletions(-) create mode 100644 tests/baselines/reference/strictSubtypeReduction.js create mode 100644 tests/baselines/reference/strictSubtypeReduction.symbols create mode 100644 tests/baselines/reference/strictSubtypeReduction.types create mode 100644 tests/baselines/reference/strictSubtypeReductionStrictMode.errors.txt create mode 100644 tests/baselines/reference/strictSubtypeReductionStrictMode.js create mode 100644 tests/baselines/reference/strictSubtypeReductionStrictMode.symbols create mode 100644 tests/baselines/reference/strictSubtypeReductionStrictMode.types create mode 100644 tests/cases/compiler/strictSubtypeReduction.ts create mode 100644 tests/cases/compiler/strictSubtypeReductionStrictMode.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9dfb4a7e112c2..cc45e70633c78 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17681,7 +17681,7 @@ namespace ts { target: Signature, ignoreReturnTypes: boolean): boolean { return compareSignaturesRelated(source, target, ignoreReturnTypes ? SignatureCheckMode.IgnoreReturnTypes : 0, /*reportErrors*/ false, - /*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; + /*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined, assignableRelation) !== Ternary.False; } type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; @@ -17705,7 +17705,8 @@ namespace ts { errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, - reportUnreliableMarkers: TypeMapper | undefined): Ternary { + reportUnreliableMarkers: TypeMapper | undefined, + relation: typeof strictSubtypeRelation): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -17735,8 +17736,8 @@ namespace ts { } const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown; - const strictVariance = !(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && - kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor; + const strictVariance = relation === strictSubtypeRelation || (!(checkMode & SignatureCheckMode.Callback) && strictFunctionTypes && kind !== SyntaxKind.MethodDeclaration && + kind !== SyntaxKind.MethodSignature && kind !== SyntaxKind.Constructor); let result = Ternary.True; const sourceThisType = getThisTypeOfSignature(source); @@ -17776,7 +17777,7 @@ namespace ts { const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); let related = callbacks ? - compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : + compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers, relation) : !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { @@ -20173,7 +20174,7 @@ namespace ts { */ function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary { return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, - relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, makeFunctionTypeMapper(reportUnreliableMarkers)); + relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, makeFunctionTypeMapper(reportUnreliableMarkers), relation); } function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { diff --git a/tests/baselines/reference/arrayLiteralWithMultipleBestCommonTypes.types b/tests/baselines/reference/arrayLiteralWithMultipleBestCommonTypes.types index a7553fd5cd5f0..6572893f90013 100644 --- a/tests/baselines/reference/arrayLiteralWithMultipleBestCommonTypes.types +++ b/tests/baselines/reference/arrayLiteralWithMultipleBestCommonTypes.types @@ -36,8 +36,8 @@ var cs = [a, b, c]; // { x: number; y?: number };[] >c : { x: number; a?: number; } var ds = [(x: Object) => 1, (x: string) => 2]; // { (x:Object) => number }[] ->ds : ((x: Object) => number)[] ->[(x: Object) => 1, (x: string) => 2] : ((x: Object) => number)[] +>ds : ((x: string) => number)[] +>[(x: Object) => 1, (x: string) => 2] : ((x: string) => number)[] >(x: Object) => 1 : (x: Object) => number >x : Object >1 : 1 diff --git a/tests/baselines/reference/arrayOfFunctionTypes3.types b/tests/baselines/reference/arrayOfFunctionTypes3.types index 4dd258645a6f2..b4ea3b59ba10a 100644 --- a/tests/baselines/reference/arrayOfFunctionTypes3.types +++ b/tests/baselines/reference/arrayOfFunctionTypes3.types @@ -50,28 +50,28 @@ var c: { (x: number): number; (x: any): any; }; >x : any var z = [a, b, c]; ->z : { (x: number): number; (x: any): any; }[] ->[a, b, c] : { (x: number): number; (x: any): any; }[] +>z : ({ (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; })[] +>[a, b, c] : ({ (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; })[] >a : { (x: number): number; (x: string): string; } >b : { (x: number): number; (x: string): string; } >c : { (x: number): number; (x: any): any; } var r4 = z[0]; ->r4 : { (x: number): number; (x: any): any; } ->z[0] : { (x: number): number; (x: any): any; } ->z : { (x: number): number; (x: any): any; }[] +>r4 : { (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; } +>z[0] : { (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; } +>z : ({ (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; })[] >0 : 0 var r5 = r4(''); // any not string >r5 : any >r4('') : any ->r4 : { (x: number): number; (x: any): any; } +>r4 : { (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; } >'' : "" var r5b = r4(1); >r5b : number >r4(1) : number ->r4 : { (x: number): number; (x: any): any; } +>r4 : { (x: number): number; (x: string): string; } | { (x: number): number; (x: any): any; } >1 : 1 var a2: { <T>(x: T): number; (x: string): string;}; diff --git a/tests/baselines/reference/bestChoiceType.symbols b/tests/baselines/reference/bestChoiceType.symbols index c7732890347d0..0072356223368 100644 --- a/tests/baselines/reference/bestChoiceType.symbols +++ b/tests/baselines/reference/bestChoiceType.symbols @@ -2,14 +2,12 @@ // Repro from #10041 (''.match(/ /) || []).map(s => s.toLowerCase()); ->(''.match(/ /) || []).map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>(''.match(/ /) || []).map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >''.match : Symbol(String.match, Decl(lib.es5.d.ts, --, --)) >match : Symbol(String.match, Decl(lib.es5.d.ts, --, --)) ->map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 2, 26)) ->s.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 2, 26)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) // Similar cases @@ -27,13 +25,11 @@ function f1() { let z = y.map(s => s.toLowerCase()); >z : Symbol(z, Decl(bestChoiceType.ts, 9, 7)) ->y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >y : Symbol(y, Decl(bestChoiceType.ts, 8, 7)) ->map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 9, 18)) ->s.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 9, 18)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) } function f2() { @@ -51,12 +47,10 @@ function f2() { let z = y.map(s => s.toLowerCase()); >z : Symbol(z, Decl(bestChoiceType.ts, 15, 7)) ->y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >y : Symbol(y, Decl(bestChoiceType.ts, 14, 7)) ->map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 15, 18)) ->s.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) >s : Symbol(s, Decl(bestChoiceType.ts, 15, 18)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) } diff --git a/tests/baselines/reference/bestChoiceType.types b/tests/baselines/reference/bestChoiceType.types index 49997d1e273cc..95fc6fb0ca5c3 100644 --- a/tests/baselines/reference/bestChoiceType.types +++ b/tests/baselines/reference/bestChoiceType.types @@ -2,23 +2,23 @@ // Repro from #10041 (''.match(/ /) || []).map(s => s.toLowerCase()); ->(''.match(/ /) || []).map(s => s.toLowerCase()) : string[] ->(''.match(/ /) || []).map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->(''.match(/ /) || []) : RegExpMatchArray ->''.match(/ /) || [] : RegExpMatchArray +>(''.match(/ /) || []).map(s => s.toLowerCase()) : any[] +>(''.match(/ /) || []).map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>(''.match(/ /) || []) : RegExpMatchArray | never[] +>''.match(/ /) || [] : RegExpMatchArray | never[] >''.match(/ /) : RegExpMatchArray | null >''.match : (regexp: string | RegExp) => RegExpMatchArray | null >'' : "" >match : (regexp: string | RegExp) => RegExpMatchArray | null >/ / : RegExp >[] : never[] ->map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->s => s.toLowerCase() : (s: string) => string ->s : string ->s.toLowerCase() : string ->s.toLowerCase : () => string ->s : string ->toLowerCase : () => string +>map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>s => s.toLowerCase() : (s: any) => any +>s : any +>s.toLowerCase() : any +>s.toLowerCase : any +>s : any +>toLowerCase : any // Similar cases @@ -34,23 +34,23 @@ function f1() { >/ / : RegExp let y = x || []; ->y : RegExpMatchArray ->x || [] : RegExpMatchArray +>y : RegExpMatchArray | never[] +>x || [] : RegExpMatchArray | never[] >x : RegExpMatchArray | null >[] : never[] let z = y.map(s => s.toLowerCase()); ->z : string[] ->y.map(s => s.toLowerCase()) : string[] ->y.map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->y : RegExpMatchArray ->map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->s => s.toLowerCase() : (s: string) => string ->s : string ->s.toLowerCase() : string ->s.toLowerCase : () => string ->s : string ->toLowerCase : () => string +>z : any[] +>y.map(s => s.toLowerCase()) : any[] +>y.map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>y : RegExpMatchArray | never[] +>map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>s => s.toLowerCase() : (s: any) => any +>s : any +>s.toLowerCase() : any +>s.toLowerCase : any +>s : any +>toLowerCase : any } function f2() { @@ -65,23 +65,23 @@ function f2() { >/ / : RegExp let y = x ? x : []; ->y : RegExpMatchArray ->x ? x : [] : RegExpMatchArray +>y : RegExpMatchArray | never[] +>x ? x : [] : RegExpMatchArray | never[] >x : RegExpMatchArray | null >x : RegExpMatchArray >[] : never[] let z = y.map(s => s.toLowerCase()); ->z : string[] ->y.map(s => s.toLowerCase()) : string[] ->y.map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->y : RegExpMatchArray ->map : <U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] ->s => s.toLowerCase() : (s: string) => string ->s : string ->s.toLowerCase() : string ->s.toLowerCase : () => string ->s : string ->toLowerCase : () => string +>z : any[] +>y.map(s => s.toLowerCase()) : any[] +>y.map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>y : RegExpMatchArray | never[] +>map : (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) +>s => s.toLowerCase() : (s: any) => any +>s : any +>s.toLowerCase() : any +>s.toLowerCase : any +>s : any +>toLowerCase : any } diff --git a/tests/baselines/reference/contextualTypingArrayOfLambdas.types b/tests/baselines/reference/contextualTypingArrayOfLambdas.types index 36b8aaa715f6f..ffe589c092927 100644 --- a/tests/baselines/reference/contextualTypingArrayOfLambdas.types +++ b/tests/baselines/reference/contextualTypingArrayOfLambdas.types @@ -23,8 +23,8 @@ class C extends A { } var xs = [(x: A) => { }, (x: B) => { }, (x: C) => { }]; ->xs : ((x: A) => void)[] ->[(x: A) => { }, (x: B) => { }, (x: C) => { }] : ((x: A) => void)[] +>xs : (((x: B) => void) | ((x: C) => void))[] +>[(x: A) => { }, (x: B) => { }, (x: C) => { }] : (((x: B) => void) | ((x: C) => void))[] >(x: A) => { } : (x: A) => void >x : A >(x: B) => { } : (x: B) => void diff --git a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.types b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.types index 51bde63a33b80..ff1d3b3e6939a 100644 --- a/tests/baselines/reference/flatArrayNoExcessiveStackDepth.types +++ b/tests/baselines/reference/flatArrayNoExcessiveStackDepth.types @@ -36,8 +36,8 @@ const repro_43249 = (value: unknown) => { >"No" : "No" } const match = value.match(/anything/) || []; ->match : RegExpMatchArray ->value.match(/anything/) || [] : RegExpMatchArray +>match : RegExpMatchArray | never[] +>value.match(/anything/) || [] : RegExpMatchArray | never[] >value.match(/anything/) : RegExpMatchArray | null >value.match : { (regexp: string | RegExp): RegExpMatchArray | null; (matcher: { [Symbol.match](string: string): RegExpMatchArray | null; }): RegExpMatchArray | null; } >value : string @@ -48,7 +48,7 @@ const repro_43249 = (value: unknown) => { const [, extracted] = match; > : undefined >extracted : string ->match : RegExpMatchArray +>match : RegExpMatchArray | never[] }; diff --git a/tests/baselines/reference/initializedDestructuringAssignmentTypes.types b/tests/baselines/reference/initializedDestructuringAssignmentTypes.types index 333fc5d92ccd8..07fd73428cf33 100644 --- a/tests/baselines/reference/initializedDestructuringAssignmentTypes.types +++ b/tests/baselines/reference/initializedDestructuringAssignmentTypes.types @@ -3,7 +3,7 @@ const [, a = ''] = ''.match('') || []; > : undefined >a : string >'' : "" ->''.match('') || [] : RegExpMatchArray +>''.match('') || [] : RegExpMatchArray | undefined[] >''.match('') : RegExpMatchArray >''.match : (regexp: string | RegExp) => RegExpMatchArray >'' : "" diff --git a/tests/baselines/reference/strictSubtypeReduction.js b/tests/baselines/reference/strictSubtypeReduction.js new file mode 100644 index 0000000000000..c373f2c1f3ab7 --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReduction.js @@ -0,0 +1,61 @@ +//// [strictSubtypeReduction.ts] +// Repro from #41977 + +class S1 { + static f(a: number | string): void { } +} + +class S2 { + static f(a: number): void { } + static g(a: number): void { } +} + +function f(a: number): void { } +function g(a: number): void { } + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +type T2 = typeof g; + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +const y2 = [S1.f, g]; +const y3 = [S1.f, S2.f]; +const y4 = [S1.f, S2.g]; + +// All assignments should be errors in strict mode, but won't be without strict function types on + +const x1: ((ctrl: number | string) => void)[] = y1; +const x2: ((ctrl: number | string) => void)[] = y2; +const x3: ((ctrl: number | string) => void)[] = y3; +const x4: ((ctrl: number | string) => void)[] = y4; + +//// [strictSubtypeReduction.js] +// Repro from #41977 +var S1 = /** @class */ (function () { + function S1() { + } + S1.f = function (a) { }; + return S1; +}()); +var S2 = /** @class */ (function () { + function S2() { + } + S2.f = function (a) { }; + S2.g = function (a) { }; + return S2; +}()); +function f(a) { } +function g(a) { } +// All should have type ((a: number) => void)[] +var y1 = [S1.f, f]; +var y2 = [S1.f, g]; +var y3 = [S1.f, S2.f]; +var y4 = [S1.f, S2.g]; +// All assignments should be errors in strict mode, but won't be without strict function types on +var x1 = y1; +var x2 = y2; +var x3 = y3; +var x4 = y4; diff --git a/tests/baselines/reference/strictSubtypeReduction.symbols b/tests/baselines/reference/strictSubtypeReduction.symbols new file mode 100644 index 0000000000000..46f2f98267de0 --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReduction.symbols @@ -0,0 +1,99 @@ +=== tests/cases/compiler/strictSubtypeReduction.ts === +// Repro from #41977 + +class S1 { +>S1 : Symbol(S1, Decl(strictSubtypeReduction.ts, 0, 0)) + + static f(a: number | string): void { } +>f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>a : Symbol(a, Decl(strictSubtypeReduction.ts, 3, 13)) +} + +class S2 { +>S2 : Symbol(S2, Decl(strictSubtypeReduction.ts, 4, 1)) + + static f(a: number): void { } +>f : Symbol(S2.f, Decl(strictSubtypeReduction.ts, 6, 10)) +>a : Symbol(a, Decl(strictSubtypeReduction.ts, 7, 13)) + + static g(a: number): void { } +>g : Symbol(S2.g, Decl(strictSubtypeReduction.ts, 7, 33)) +>a : Symbol(a, Decl(strictSubtypeReduction.ts, 8, 13)) +} + +function f(a: number): void { } +>f : Symbol(f, Decl(strictSubtypeReduction.ts, 9, 1)) +>a : Symbol(a, Decl(strictSubtypeReduction.ts, 11, 11)) + +function g(a: number): void { } +>g : Symbol(g, Decl(strictSubtypeReduction.ts, 11, 31)) +>a : Symbol(a, Decl(strictSubtypeReduction.ts, 12, 11)) + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +>T1 : Symbol(T1, Decl(strictSubtypeReduction.ts, 12, 31)) +>S2.g : Symbol(S2.g, Decl(strictSubtypeReduction.ts, 7, 33)) +>S2 : Symbol(S2, Decl(strictSubtypeReduction.ts, 4, 1)) +>g : Symbol(S2.g, Decl(strictSubtypeReduction.ts, 7, 33)) + +type T2 = typeof g; +>T2 : Symbol(T2, Decl(strictSubtypeReduction.ts, 16, 22)) +>g : Symbol(g, Decl(strictSubtypeReduction.ts, 11, 31)) + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +>y1 : Symbol(y1, Decl(strictSubtypeReduction.ts, 21, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReduction.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>f : Symbol(f, Decl(strictSubtypeReduction.ts, 9, 1)) + +const y2 = [S1.f, g]; +>y2 : Symbol(y2, Decl(strictSubtypeReduction.ts, 22, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReduction.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>g : Symbol(g, Decl(strictSubtypeReduction.ts, 11, 31)) + +const y3 = [S1.f, S2.f]; +>y3 : Symbol(y3, Decl(strictSubtypeReduction.ts, 23, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReduction.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S2.f : Symbol(S2.f, Decl(strictSubtypeReduction.ts, 6, 10)) +>S2 : Symbol(S2, Decl(strictSubtypeReduction.ts, 4, 1)) +>f : Symbol(S2.f, Decl(strictSubtypeReduction.ts, 6, 10)) + +const y4 = [S1.f, S2.g]; +>y4 : Symbol(y4, Decl(strictSubtypeReduction.ts, 24, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReduction.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReduction.ts, 2, 10)) +>S2.g : Symbol(S2.g, Decl(strictSubtypeReduction.ts, 7, 33)) +>S2 : Symbol(S2, Decl(strictSubtypeReduction.ts, 4, 1)) +>g : Symbol(S2.g, Decl(strictSubtypeReduction.ts, 7, 33)) + +// All assignments should be errors in strict mode, but won't be without strict function types on + +const x1: ((ctrl: number | string) => void)[] = y1; +>x1 : Symbol(x1, Decl(strictSubtypeReduction.ts, 28, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReduction.ts, 28, 12)) +>y1 : Symbol(y1, Decl(strictSubtypeReduction.ts, 21, 5)) + +const x2: ((ctrl: number | string) => void)[] = y2; +>x2 : Symbol(x2, Decl(strictSubtypeReduction.ts, 29, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReduction.ts, 29, 12)) +>y2 : Symbol(y2, Decl(strictSubtypeReduction.ts, 22, 5)) + +const x3: ((ctrl: number | string) => void)[] = y3; +>x3 : Symbol(x3, Decl(strictSubtypeReduction.ts, 30, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReduction.ts, 30, 12)) +>y3 : Symbol(y3, Decl(strictSubtypeReduction.ts, 23, 5)) + +const x4: ((ctrl: number | string) => void)[] = y4; +>x4 : Symbol(x4, Decl(strictSubtypeReduction.ts, 31, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReduction.ts, 31, 12)) +>y4 : Symbol(y4, Decl(strictSubtypeReduction.ts, 24, 5)) + diff --git a/tests/baselines/reference/strictSubtypeReduction.types b/tests/baselines/reference/strictSubtypeReduction.types new file mode 100644 index 0000000000000..aac67307d3710 --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReduction.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/strictSubtypeReduction.ts === +// Repro from #41977 + +class S1 { +>S1 : S1 + + static f(a: number | string): void { } +>f : (a: number | string) => void +>a : string | number +} + +class S2 { +>S2 : S2 + + static f(a: number): void { } +>f : (a: number) => void +>a : number + + static g(a: number): void { } +>g : (a: number) => void +>a : number +} + +function f(a: number): void { } +>f : (a: number) => void +>a : number + +function g(a: number): void { } +>g : (a: number) => void +>a : number + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +>T1 : (a: number) => void +>S2.g : (a: number) => void +>S2 : typeof S2 +>g : (a: number) => void + +type T2 = typeof g; +>T2 : (a: number) => void +>g : (a: number) => void + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +>y1 : ((a: number) => void)[] +>[S1.f, f] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>f : (a: number) => void + +const y2 = [S1.f, g]; +>y2 : ((a: number) => void)[] +>[S1.f, g] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>g : (a: number) => void + +const y3 = [S1.f, S2.f]; +>y3 : ((a: number) => void)[] +>[S1.f, S2.f] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>S2.f : (a: number) => void +>S2 : typeof S2 +>f : (a: number) => void + +const y4 = [S1.f, S2.g]; +>y4 : ((a: number) => void)[] +>[S1.f, S2.g] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>S2.g : (a: number) => void +>S2 : typeof S2 +>g : (a: number) => void + +// All assignments should be errors in strict mode, but won't be without strict function types on + +const x1: ((ctrl: number | string) => void)[] = y1; +>x1 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y1 : ((a: number) => void)[] + +const x2: ((ctrl: number | string) => void)[] = y2; +>x2 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y2 : ((a: number) => void)[] + +const x3: ((ctrl: number | string) => void)[] = y3; +>x3 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y3 : ((a: number) => void)[] + +const x4: ((ctrl: number | string) => void)[] = y4; +>x4 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y4 : ((a: number) => void)[] + diff --git a/tests/baselines/reference/strictSubtypeReductionStrictMode.errors.txt b/tests/baselines/reference/strictSubtypeReductionStrictMode.errors.txt new file mode 100644 index 0000000000000..077d76d3e3b8e --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReductionStrictMode.errors.txt @@ -0,0 +1,79 @@ +tests/cases/compiler/strictSubtypeReductionStrictMode.ts(29,7): error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. + Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. + Types of parameters 'a' and 'ctrl' are incompatible. + Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/compiler/strictSubtypeReductionStrictMode.ts(30,7): error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. + Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. + Types of parameters 'a' and 'ctrl' are incompatible. + Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/compiler/strictSubtypeReductionStrictMode.ts(31,7): error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. + Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. + Types of parameters 'a' and 'ctrl' are incompatible. + Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. +tests/cases/compiler/strictSubtypeReductionStrictMode.ts(32,7): error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. + Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. + Types of parameters 'a' and 'ctrl' are incompatible. + Type 'string | number' is not assignable to type 'number'. + Type 'string' is not assignable to type 'number'. + + +==== tests/cases/compiler/strictSubtypeReductionStrictMode.ts (4 errors) ==== + // Repro from #41977 + + class S1 { + static f(a: number | string): void { } + } + + class S2 { + static f(a: number): void { } + static g(a: number): void { } + } + + function f(a: number): void { } + function g(a: number): void { } + + // Declaring the following type aliases should have no effect + + type T1 = typeof S2.g; + type T2 = typeof g; + + // All should have type ((a: number) => void)[] + + const y1 = [S1.f, f]; + const y2 = [S1.f, g]; + const y3 = [S1.f, S2.f]; + const y4 = [S1.f, S2.g]; + + // All assignments should be errors + + const x1: ((ctrl: number | string) => void)[] = y1; + ~~ +!!! error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. +!!! error TS2322: Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. +!!! error TS2322: Types of parameters 'a' and 'ctrl' are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + const x2: ((ctrl: number | string) => void)[] = y2; + ~~ +!!! error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. +!!! error TS2322: Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. +!!! error TS2322: Types of parameters 'a' and 'ctrl' are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + const x3: ((ctrl: number | string) => void)[] = y3; + ~~ +!!! error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. +!!! error TS2322: Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. +!!! error TS2322: Types of parameters 'a' and 'ctrl' are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. + const x4: ((ctrl: number | string) => void)[] = y4; + ~~ +!!! error TS2322: Type '((a: number) => void)[]' is not assignable to type '((ctrl: string | number) => void)[]'. +!!! error TS2322: Type '(a: number) => void' is not assignable to type '(ctrl: string | number) => void'. +!!! error TS2322: Types of parameters 'a' and 'ctrl' are incompatible. +!!! error TS2322: Type 'string | number' is not assignable to type 'number'. +!!! error TS2322: Type 'string' is not assignable to type 'number'. \ No newline at end of file diff --git a/tests/baselines/reference/strictSubtypeReductionStrictMode.js b/tests/baselines/reference/strictSubtypeReductionStrictMode.js new file mode 100644 index 0000000000000..5e5d520251cb0 --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReductionStrictMode.js @@ -0,0 +1,62 @@ +//// [strictSubtypeReductionStrictMode.ts] +// Repro from #41977 + +class S1 { + static f(a: number | string): void { } +} + +class S2 { + static f(a: number): void { } + static g(a: number): void { } +} + +function f(a: number): void { } +function g(a: number): void { } + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +type T2 = typeof g; + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +const y2 = [S1.f, g]; +const y3 = [S1.f, S2.f]; +const y4 = [S1.f, S2.g]; + +// All assignments should be errors + +const x1: ((ctrl: number | string) => void)[] = y1; +const x2: ((ctrl: number | string) => void)[] = y2; +const x3: ((ctrl: number | string) => void)[] = y3; +const x4: ((ctrl: number | string) => void)[] = y4; + +//// [strictSubtypeReductionStrictMode.js] +"use strict"; +// Repro from #41977 +var S1 = /** @class */ (function () { + function S1() { + } + S1.f = function (a) { }; + return S1; +}()); +var S2 = /** @class */ (function () { + function S2() { + } + S2.f = function (a) { }; + S2.g = function (a) { }; + return S2; +}()); +function f(a) { } +function g(a) { } +// All should have type ((a: number) => void)[] +var y1 = [S1.f, f]; +var y2 = [S1.f, g]; +var y3 = [S1.f, S2.f]; +var y4 = [S1.f, S2.g]; +// All assignments should be errors +var x1 = y1; +var x2 = y2; +var x3 = y3; +var x4 = y4; diff --git a/tests/baselines/reference/strictSubtypeReductionStrictMode.symbols b/tests/baselines/reference/strictSubtypeReductionStrictMode.symbols new file mode 100644 index 0000000000000..95ad6cff755ae --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReductionStrictMode.symbols @@ -0,0 +1,99 @@ +=== tests/cases/compiler/strictSubtypeReductionStrictMode.ts === +// Repro from #41977 + +class S1 { +>S1 : Symbol(S1, Decl(strictSubtypeReductionStrictMode.ts, 0, 0)) + + static f(a: number | string): void { } +>f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>a : Symbol(a, Decl(strictSubtypeReductionStrictMode.ts, 3, 13)) +} + +class S2 { +>S2 : Symbol(S2, Decl(strictSubtypeReductionStrictMode.ts, 4, 1)) + + static f(a: number): void { } +>f : Symbol(S2.f, Decl(strictSubtypeReductionStrictMode.ts, 6, 10)) +>a : Symbol(a, Decl(strictSubtypeReductionStrictMode.ts, 7, 13)) + + static g(a: number): void { } +>g : Symbol(S2.g, Decl(strictSubtypeReductionStrictMode.ts, 7, 33)) +>a : Symbol(a, Decl(strictSubtypeReductionStrictMode.ts, 8, 13)) +} + +function f(a: number): void { } +>f : Symbol(f, Decl(strictSubtypeReductionStrictMode.ts, 9, 1)) +>a : Symbol(a, Decl(strictSubtypeReductionStrictMode.ts, 11, 11)) + +function g(a: number): void { } +>g : Symbol(g, Decl(strictSubtypeReductionStrictMode.ts, 11, 31)) +>a : Symbol(a, Decl(strictSubtypeReductionStrictMode.ts, 12, 11)) + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +>T1 : Symbol(T1, Decl(strictSubtypeReductionStrictMode.ts, 12, 31)) +>S2.g : Symbol(S2.g, Decl(strictSubtypeReductionStrictMode.ts, 7, 33)) +>S2 : Symbol(S2, Decl(strictSubtypeReductionStrictMode.ts, 4, 1)) +>g : Symbol(S2.g, Decl(strictSubtypeReductionStrictMode.ts, 7, 33)) + +type T2 = typeof g; +>T2 : Symbol(T2, Decl(strictSubtypeReductionStrictMode.ts, 16, 22)) +>g : Symbol(g, Decl(strictSubtypeReductionStrictMode.ts, 11, 31)) + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +>y1 : Symbol(y1, Decl(strictSubtypeReductionStrictMode.ts, 21, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReductionStrictMode.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>f : Symbol(f, Decl(strictSubtypeReductionStrictMode.ts, 9, 1)) + +const y2 = [S1.f, g]; +>y2 : Symbol(y2, Decl(strictSubtypeReductionStrictMode.ts, 22, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReductionStrictMode.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>g : Symbol(g, Decl(strictSubtypeReductionStrictMode.ts, 11, 31)) + +const y3 = [S1.f, S2.f]; +>y3 : Symbol(y3, Decl(strictSubtypeReductionStrictMode.ts, 23, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReductionStrictMode.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S2.f : Symbol(S2.f, Decl(strictSubtypeReductionStrictMode.ts, 6, 10)) +>S2 : Symbol(S2, Decl(strictSubtypeReductionStrictMode.ts, 4, 1)) +>f : Symbol(S2.f, Decl(strictSubtypeReductionStrictMode.ts, 6, 10)) + +const y4 = [S1.f, S2.g]; +>y4 : Symbol(y4, Decl(strictSubtypeReductionStrictMode.ts, 24, 5)) +>S1.f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S1 : Symbol(S1, Decl(strictSubtypeReductionStrictMode.ts, 0, 0)) +>f : Symbol(S1.f, Decl(strictSubtypeReductionStrictMode.ts, 2, 10)) +>S2.g : Symbol(S2.g, Decl(strictSubtypeReductionStrictMode.ts, 7, 33)) +>S2 : Symbol(S2, Decl(strictSubtypeReductionStrictMode.ts, 4, 1)) +>g : Symbol(S2.g, Decl(strictSubtypeReductionStrictMode.ts, 7, 33)) + +// All assignments should be errors + +const x1: ((ctrl: number | string) => void)[] = y1; +>x1 : Symbol(x1, Decl(strictSubtypeReductionStrictMode.ts, 28, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReductionStrictMode.ts, 28, 12)) +>y1 : Symbol(y1, Decl(strictSubtypeReductionStrictMode.ts, 21, 5)) + +const x2: ((ctrl: number | string) => void)[] = y2; +>x2 : Symbol(x2, Decl(strictSubtypeReductionStrictMode.ts, 29, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReductionStrictMode.ts, 29, 12)) +>y2 : Symbol(y2, Decl(strictSubtypeReductionStrictMode.ts, 22, 5)) + +const x3: ((ctrl: number | string) => void)[] = y3; +>x3 : Symbol(x3, Decl(strictSubtypeReductionStrictMode.ts, 30, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReductionStrictMode.ts, 30, 12)) +>y3 : Symbol(y3, Decl(strictSubtypeReductionStrictMode.ts, 23, 5)) + +const x4: ((ctrl: number | string) => void)[] = y4; +>x4 : Symbol(x4, Decl(strictSubtypeReductionStrictMode.ts, 31, 5)) +>ctrl : Symbol(ctrl, Decl(strictSubtypeReductionStrictMode.ts, 31, 12)) +>y4 : Symbol(y4, Decl(strictSubtypeReductionStrictMode.ts, 24, 5)) + diff --git a/tests/baselines/reference/strictSubtypeReductionStrictMode.types b/tests/baselines/reference/strictSubtypeReductionStrictMode.types new file mode 100644 index 0000000000000..dbd29a78efe62 --- /dev/null +++ b/tests/baselines/reference/strictSubtypeReductionStrictMode.types @@ -0,0 +1,103 @@ +=== tests/cases/compiler/strictSubtypeReductionStrictMode.ts === +// Repro from #41977 + +class S1 { +>S1 : S1 + + static f(a: number | string): void { } +>f : (a: number | string) => void +>a : string | number +} + +class S2 { +>S2 : S2 + + static f(a: number): void { } +>f : (a: number) => void +>a : number + + static g(a: number): void { } +>g : (a: number) => void +>a : number +} + +function f(a: number): void { } +>f : (a: number) => void +>a : number + +function g(a: number): void { } +>g : (a: number) => void +>a : number + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +>T1 : (a: number) => void +>S2.g : (a: number) => void +>S2 : typeof S2 +>g : (a: number) => void + +type T2 = typeof g; +>T2 : (a: number) => void +>g : (a: number) => void + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +>y1 : ((a: number) => void)[] +>[S1.f, f] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>f : (a: number) => void + +const y2 = [S1.f, g]; +>y2 : ((a: number) => void)[] +>[S1.f, g] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>g : (a: number) => void + +const y3 = [S1.f, S2.f]; +>y3 : ((a: number) => void)[] +>[S1.f, S2.f] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>S2.f : (a: number) => void +>S2 : typeof S2 +>f : (a: number) => void + +const y4 = [S1.f, S2.g]; +>y4 : ((a: number) => void)[] +>[S1.f, S2.g] : ((a: number) => void)[] +>S1.f : (a: string | number) => void +>S1 : typeof S1 +>f : (a: string | number) => void +>S2.g : (a: number) => void +>S2 : typeof S2 +>g : (a: number) => void + +// All assignments should be errors + +const x1: ((ctrl: number | string) => void)[] = y1; +>x1 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y1 : ((a: number) => void)[] + +const x2: ((ctrl: number | string) => void)[] = y2; +>x2 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y2 : ((a: number) => void)[] + +const x3: ((ctrl: number | string) => void)[] = y3; +>x3 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y3 : ((a: number) => void)[] + +const x4: ((ctrl: number | string) => void)[] = y4; +>x4 : ((ctrl: number | string) => void)[] +>ctrl : string | number +>y4 : ((a: number) => void)[] + diff --git a/tests/baselines/reference/subtypingWithCallSignatures3.types b/tests/baselines/reference/subtypingWithCallSignatures3.types index 7116d132b7d2b..52310f1cfa573 100644 --- a/tests/baselines/reference/subtypingWithCallSignatures3.types +++ b/tests/baselines/reference/subtypingWithCallSignatures3.types @@ -305,14 +305,14 @@ module Errors { >r4arg : <T extends Derived>(...x: T[]) => T var r4a = [r4arg2, r4arg]; ->r4a : ((...x: Base[]) => Base)[] ->[r4arg2, r4arg] : ((...x: Base[]) => Base)[] +>r4a : ((<T extends Derived>(...x: T[]) => T) | ((...x: Base[]) => Base))[] +>[r4arg2, r4arg] : ((<T extends Derived>(...x: T[]) => T) | ((...x: Base[]) => Base))[] >r4arg2 : (...x: Base[]) => Base >r4arg : <T extends Derived>(...x: T[]) => T var r4b = [r4arg, r4arg2]; ->r4b : ((...x: Base[]) => Base)[] ->[r4arg, r4arg2] : ((...x: Base[]) => Base)[] +>r4b : ((<T extends Derived>(...x: T[]) => T) | ((...x: Base[]) => Base))[] +>[r4arg, r4arg2] : ((<T extends Derived>(...x: T[]) => T) | ((...x: Base[]) => Base))[] >r4arg : <T extends Derived>(...x: T[]) => T >r4arg2 : (...x: Base[]) => Base @@ -342,14 +342,14 @@ module Errors { >r5arg : <T extends Derived>(x: T, y: T) => T var r5a = [r5arg2, r5arg]; ->r5a : ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] ->[r5arg2, r5arg] : ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] +>r5a : ((<T extends Derived>(x: T, y: T) => T) | ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] +>[r5arg2, r5arg] : ((<T extends Derived>(x: T, y: T) => T) | ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] >r5arg2 : (x: { foo: string; }, y: { foo: string; bar: string; }) => Base >r5arg : <T extends Derived>(x: T, y: T) => T var r5b = [r5arg, r5arg2]; ->r5b : ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] ->[r5arg, r5arg2] : ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] +>r5b : ((<T extends Derived>(x: T, y: T) => T) | ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] +>[r5arg, r5arg2] : ((<T extends Derived>(x: T, y: T) => T) | ((x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] >r5arg : <T extends Derived>(x: T, y: T) => T >r5arg2 : (x: { foo: string; }, y: { foo: string; bar: string; }) => Base diff --git a/tests/baselines/reference/subtypingWithConstructSignatures3.types b/tests/baselines/reference/subtypingWithConstructSignatures3.types index 5cf176caa0934..c78033a447c7a 100644 --- a/tests/baselines/reference/subtypingWithConstructSignatures3.types +++ b/tests/baselines/reference/subtypingWithConstructSignatures3.types @@ -276,14 +276,14 @@ module Errors { >r4arg1 : new <T extends Derived>(...x: T[]) => T var r4a = [r4arg2, r4arg1]; ->r4a : (new (...x: Base[]) => Base)[] ->[r4arg2, r4arg1] : (new (...x: Base[]) => Base)[] +>r4a : ((new <T extends Derived>(...x: T[]) => T) | (new (...x: Base[]) => Base))[] +>[r4arg2, r4arg1] : ((new <T extends Derived>(...x: T[]) => T) | (new (...x: Base[]) => Base))[] >r4arg2 : new (...x: Base[]) => Base >r4arg1 : new <T extends Derived>(...x: T[]) => T var r4b = [r4arg1, r4arg2]; ->r4b : (new (...x: Base[]) => Base)[] ->[r4arg1, r4arg2] : (new (...x: Base[]) => Base)[] +>r4b : ((new <T extends Derived>(...x: T[]) => T) | (new (...x: Base[]) => Base))[] +>[r4arg1, r4arg2] : ((new <T extends Derived>(...x: T[]) => T) | (new (...x: Base[]) => Base))[] >r4arg1 : new <T extends Derived>(...x: T[]) => T >r4arg2 : new (...x: Base[]) => Base @@ -307,14 +307,14 @@ module Errors { >r5arg1 : new <T extends Derived>(x: T, y: T) => T var r5a = [r5arg2, r5arg1]; ->r5a : (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] ->[r5arg2, r5arg1] : (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] +>r5a : ((new <T extends Derived>(x: T, y: T) => T) | (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] +>[r5arg2, r5arg1] : ((new <T extends Derived>(x: T, y: T) => T) | (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] >r5arg2 : new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base >r5arg1 : new <T extends Derived>(x: T, y: T) => T var r5b = [r5arg1, r5arg2]; ->r5b : (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] ->[r5arg1, r5arg2] : (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base)[] +>r5b : ((new <T extends Derived>(x: T, y: T) => T) | (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] +>[r5arg1, r5arg2] : ((new <T extends Derived>(x: T, y: T) => T) | (new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base))[] >r5arg1 : new <T extends Derived>(x: T, y: T) => T >r5arg2 : new (x: { foo: string; }, y: { foo: string; bar: string; }) => Base diff --git a/tests/baselines/reference/tsxUnionElementType3.errors.txt b/tests/baselines/reference/tsxUnionElementType3.errors.txt index 73d8ccb0ce2b2..e61786f2c04b2 100644 --- a/tests/baselines/reference/tsxUnionElementType3.errors.txt +++ b/tests/baselines/reference/tsxUnionElementType3.errors.txt @@ -1,7 +1,9 @@ tests/cases/conformance/jsx/file.tsx(32,17): error TS2322: Type 'string' is not assignable to type 'never'. +tests/cases/conformance/jsx/file.tsx(35,10): error TS2741: Property 'x' is missing in type '{}' but required in type '{ x: number; }'. +tests/cases/conformance/jsx/file.tsx(36,10): error TS2741: Property 'x' is missing in type '{ "data-extra": string; }' but required in type '{ x: number; }'. -==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== import React = require('react'); class RC1 extends React.Component<{x : number}, {}> { @@ -40,4 +42,10 @@ tests/cases/conformance/jsx/file.tsx(32,17): error TS2322: Type 'string' is not let a1 = <EmptyRCComp />; let a2 = <EmptyRCComp data-prop="hello" />; let b = <PartRCComp /> - let c = <PartRCComp data-extra="hello" /> \ No newline at end of file + ~~~~~~~~~~ +!!! error TS2741: Property 'x' is missing in type '{}' but required in type '{ x: number; }'. +!!! related TS2728 tests/cases/conformance/jsx/file.tsx:3:36: 'x' is declared here. + let c = <PartRCComp data-extra="hello" /> + ~~~~~~~~~~ +!!! error TS2741: Property 'x' is missing in type '{ "data-extra": string; }' but required in type '{ x: number; }'. +!!! related TS2728 tests/cases/conformance/jsx/file.tsx:3:36: 'x' is declared here. \ No newline at end of file diff --git a/tests/baselines/reference/tsxUnionElementType3.types b/tests/baselines/reference/tsxUnionElementType3.types index 5a797ea483b59..65a7ca0d25eeb 100644 --- a/tests/baselines/reference/tsxUnionElementType3.types +++ b/tests/baselines/reference/tsxUnionElementType3.types @@ -69,8 +69,8 @@ var EmptyRCComp = RC3 || RC4; >RC4 : typeof RC4 var PartRCComp = RC1 || RC4; ->PartRCComp : typeof RC4 ->RC1 || RC4 : typeof RC4 +>PartRCComp : typeof RC1 | typeof RC4 +>RC1 || RC4 : typeof RC1 | typeof RC4 >RC1 : typeof RC1 >RC4 : typeof RC4 @@ -101,11 +101,11 @@ let a2 = <EmptyRCComp data-prop="hello" />; let b = <PartRCComp /> >b : JSX.Element ><PartRCComp /> : JSX.Element ->PartRCComp : typeof RC4 +>PartRCComp : typeof RC1 | typeof RC4 let c = <PartRCComp data-extra="hello" /> >c : JSX.Element ><PartRCComp data-extra="hello" /> : JSX.Element ->PartRCComp : typeof RC4 +>PartRCComp : typeof RC1 | typeof RC4 >data-extra : string diff --git a/tests/baselines/reference/tsxUnionElementType4.errors.txt b/tests/baselines/reference/tsxUnionElementType4.errors.txt index 03cb6c62a526e..665af28a91068 100644 --- a/tests/baselines/reference/tsxUnionElementType4.errors.txt +++ b/tests/baselines/reference/tsxUnionElementType4.errors.txt @@ -1,11 +1,9 @@ tests/cases/conformance/jsx/file.tsx(32,17): error TS2322: Type 'boolean' is not assignable to type 'never'. -tests/cases/conformance/jsx/file.tsx(33,21): error TS2322: Type '{ x: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<RC4> & { children?: ReactNode; }'. - Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<RC4> & { children?: ReactNode; }'. tests/cases/conformance/jsx/file.tsx(34,22): error TS2322: Type '{ prop: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<RC3> & { children?: ReactNode; }'. Property 'prop' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<RC3> & { children?: ReactNode; }'. -==== tests/cases/conformance/jsx/file.tsx (3 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== import React = require('react'); class RC1 extends React.Component<{x : number}, {}> { @@ -42,9 +40,6 @@ tests/cases/conformance/jsx/file.tsx(34,22): error TS2322: Type '{ prop: true; } !!! error TS2322: Type 'boolean' is not assignable to type 'never'. !!! related TS6500 tests/cases/conformance/jsx/file.tsx:3:36: The expected type comes from property 'x' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes<RC1 | RC2> & { x: number; } & { children?: ReactNode; } & { x: string; } & { children?: ReactNode; }' let b = <PartRCComp x={10} /> - ~ -!!! error TS2322: Type '{ x: number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<RC4> & { children?: ReactNode; }'. -!!! error TS2322: Property 'x' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<RC4> & { children?: ReactNode; }'. let c = <EmptyRCComp prop />; ~~~~ !!! error TS2322: Type '{ prop: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<RC3> & { children?: ReactNode; }'. diff --git a/tests/baselines/reference/tsxUnionElementType4.types b/tests/baselines/reference/tsxUnionElementType4.types index c0961eb6d1644..d346b144a49e3 100644 --- a/tests/baselines/reference/tsxUnionElementType4.types +++ b/tests/baselines/reference/tsxUnionElementType4.types @@ -75,8 +75,8 @@ var EmptyRCComp = RC3 || RC4; >RC4 : typeof RC4 var PartRCComp = RC1 || RC4; ->PartRCComp : typeof RC4 ->RC1 || RC4 : typeof RC4 +>PartRCComp : typeof RC1 | typeof RC4 +>RC1 || RC4 : typeof RC1 | typeof RC4 >RC1 : typeof RC1 >RC4 : typeof RC4 @@ -90,7 +90,7 @@ let a = <RCComp x />; let b = <PartRCComp x={10} /> >b : JSX.Element ><PartRCComp x={10} /> : JSX.Element ->PartRCComp : typeof RC4 +>PartRCComp : typeof RC1 | typeof RC4 >x : number >10 : 10 diff --git a/tests/cases/compiler/strictSubtypeReduction.ts b/tests/cases/compiler/strictSubtypeReduction.ts new file mode 100644 index 0000000000000..b1dd3f18c8777 --- /dev/null +++ b/tests/cases/compiler/strictSubtypeReduction.ts @@ -0,0 +1,32 @@ +// Repro from #41977 + +class S1 { + static f(a: number | string): void { } +} + +class S2 { + static f(a: number): void { } + static g(a: number): void { } +} + +function f(a: number): void { } +function g(a: number): void { } + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +type T2 = typeof g; + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +const y2 = [S1.f, g]; +const y3 = [S1.f, S2.f]; +const y4 = [S1.f, S2.g]; + +// All assignments should be errors in strict mode, but won't be without strict function types on + +const x1: ((ctrl: number | string) => void)[] = y1; +const x2: ((ctrl: number | string) => void)[] = y2; +const x3: ((ctrl: number | string) => void)[] = y3; +const x4: ((ctrl: number | string) => void)[] = y4; \ No newline at end of file diff --git a/tests/cases/compiler/strictSubtypeReductionStrictMode.ts b/tests/cases/compiler/strictSubtypeReductionStrictMode.ts new file mode 100644 index 0000000000000..26247fb3ededd --- /dev/null +++ b/tests/cases/compiler/strictSubtypeReductionStrictMode.ts @@ -0,0 +1,33 @@ +// @strict: true +// Repro from #41977 + +class S1 { + static f(a: number | string): void { } +} + +class S2 { + static f(a: number): void { } + static g(a: number): void { } +} + +function f(a: number): void { } +function g(a: number): void { } + +// Declaring the following type aliases should have no effect + +type T1 = typeof S2.g; +type T2 = typeof g; + +// All should have type ((a: number) => void)[] + +const y1 = [S1.f, f]; +const y2 = [S1.f, g]; +const y3 = [S1.f, S2.f]; +const y4 = [S1.f, S2.g]; + +// All assignments should be errors + +const x1: ((ctrl: number | string) => void)[] = y1; +const x2: ((ctrl: number | string) => void)[] = y2; +const x3: ((ctrl: number | string) => void)[] = y3; +const x4: ((ctrl: number | string) => void)[] = y4; \ No newline at end of file