Merge pull request #26895 from Microsoft/callableErrors

Find first callable/constructable type in union when appropriate
This commit is contained in:
Daniel Rosenwasser 2018-09-07 00:06:11 -07:00 committed by GitHub
commit cf2f339a5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 190 additions and 11 deletions

View file

@ -11441,7 +11441,8 @@ namespace ts {
const bestMatchingType =
findMatchingDiscriminantType(source, target) ||
findMatchingTypeReferenceOrTypeAliasReference(source, target) ||
findBestTypeForObjectLiteral(source, target);
findBestTypeForObjectLiteral(source, target) ||
findBestTypeForInvokable(source, target);
isRelatedTo(source, bestMatchingType || targetTypes[targetTypes.length - 1], /*reportErrors*/ true);
}
@ -11472,6 +11473,15 @@ namespace ts {
}
}
function findBestTypeForInvokable(source: Type, unionTarget: UnionOrIntersectionType) {
let signatureKind = SignatureKind.Call;
const hasSignatures = getSignaturesOfType(source, signatureKind).length > 0 ||
(signatureKind = SignatureKind.Construct, getSignaturesOfType(source, signatureKind).length > 0);
if (hasSignatures) {
return find(unionTarget.types, t => getSignaturesOfType(t, signatureKind).length > 0);
}
}
// Keep this up-to-date with the same logic within `getApparentTypeOfContextualType`, since they should behave similarly
function findMatchingDiscriminantType(source: Type, target: UnionOrIntersectionType) {
let match: Type | undefined;

View file

@ -22,9 +22,9 @@ tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(58,5): error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => string) | ((a: string, b: number) => number)'.
Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => number'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => string'.
Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
==== tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts (6 errors) ====
@ -116,8 +116,8 @@ tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts(
commonMethodDifferentReturnType: (a, b) => strOrNumber,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '((a: string, b: number) => string) | ((a: string, b: number) => number)'.
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => number'.
!!! error TS2322: Type 'string | number' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
!!! error TS2322: Type '(a: string, b: number) => string | number' is not assignable to type '(a: string, b: number) => string'.
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6500 tests/cases/conformance/types/union/contextualTypeWithUnionTypeObjectLiteral.ts:35:5: The expected type comes from property 'commonMethodDifferentReturnType' which is declared here on type 'I11 | I21'
};

View file

@ -0,0 +1,40 @@
tests/cases/compiler/errorsWithInvokablesInUnions01.ts(14,12): error TS2322: Type '(x: string) => void' is not assignable to type 'ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>'.
Type '(x: string) => void' is not assignable to type 'IDirectiveLinkFn<number>'.
Types of parameters 'x' and 'scope' are incompatible.
Type 'number' is not assignable to type 'string'.
tests/cases/compiler/errorsWithInvokablesInUnions01.ts(16,12): error TS2322: Type 'typeof ctor' is not assignable to type 'ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>'.
Type 'typeof ctor' is not assignable to type 'ConstructableA'.
Type 'ctor' is not assignable to type '{ somePropA: any; }'.
Property 'somePropA' is missing in type 'ctor'.
==== tests/cases/compiler/errorsWithInvokablesInUnions01.ts (2 errors) ====
interface ConstructableA {
new(): { somePropA: any };
}
interface IDirectiveLinkFn<TScope> {
(scope: TScope): void;
}
interface IDirectivePrePost<TScope> {
pre?: IDirectiveLinkFn<TScope>;
post?: IDirectiveLinkFn<TScope>;
}
export let blah: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = (x: string) => {}
~~~~
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>'.
!!! error TS2322: Type '(x: string) => void' is not assignable to type 'IDirectiveLinkFn<number>'.
!!! error TS2322: Types of parameters 'x' and 'scope' are incompatible.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
export let ctor: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = class {
~~~~
!!! error TS2322: Type 'typeof ctor' is not assignable to type 'ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>'.
!!! error TS2322: Type 'typeof ctor' is not assignable to type 'ConstructableA'.
!!! error TS2322: Type 'ctor' is not assignable to type '{ somePropA: any; }'.
!!! error TS2322: Property 'somePropA' is missing in type 'ctor'.
someUnaccountedProp: any;
}

View file

@ -0,0 +1,30 @@
//// [errorsWithInvokablesInUnions01.ts]
interface ConstructableA {
new(): { somePropA: any };
}
interface IDirectiveLinkFn<TScope> {
(scope: TScope): void;
}
interface IDirectivePrePost<TScope> {
pre?: IDirectiveLinkFn<TScope>;
post?: IDirectiveLinkFn<TScope>;
}
export let blah: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = (x: string) => {}
export let ctor: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = class {
someUnaccountedProp: any;
}
//// [errorsWithInvokablesInUnions01.js]
"use strict";
exports.__esModule = true;
exports.blah = function (x) { };
exports.ctor = /** @class */ (function () {
function class_1() {
}
return class_1;
}());

View file

@ -0,0 +1,49 @@
=== tests/cases/compiler/errorsWithInvokablesInUnions01.ts ===
interface ConstructableA {
>ConstructableA : Symbol(ConstructableA, Decl(errorsWithInvokablesInUnions01.ts, 0, 0))
new(): { somePropA: any };
>somePropA : Symbol(somePropA, Decl(errorsWithInvokablesInUnions01.ts, 1, 10))
}
interface IDirectiveLinkFn<TScope> {
>IDirectiveLinkFn : Symbol(IDirectiveLinkFn, Decl(errorsWithInvokablesInUnions01.ts, 2, 1))
>TScope : Symbol(TScope, Decl(errorsWithInvokablesInUnions01.ts, 4, 27))
(scope: TScope): void;
>scope : Symbol(scope, Decl(errorsWithInvokablesInUnions01.ts, 5, 5))
>TScope : Symbol(TScope, Decl(errorsWithInvokablesInUnions01.ts, 4, 27))
}
interface IDirectivePrePost<TScope> {
>IDirectivePrePost : Symbol(IDirectivePrePost, Decl(errorsWithInvokablesInUnions01.ts, 6, 1))
>TScope : Symbol(TScope, Decl(errorsWithInvokablesInUnions01.ts, 8, 28))
pre?: IDirectiveLinkFn<TScope>;
>pre : Symbol(IDirectivePrePost.pre, Decl(errorsWithInvokablesInUnions01.ts, 8, 37))
>IDirectiveLinkFn : Symbol(IDirectiveLinkFn, Decl(errorsWithInvokablesInUnions01.ts, 2, 1))
>TScope : Symbol(TScope, Decl(errorsWithInvokablesInUnions01.ts, 8, 28))
post?: IDirectiveLinkFn<TScope>;
>post : Symbol(IDirectivePrePost.post, Decl(errorsWithInvokablesInUnions01.ts, 9, 35))
>IDirectiveLinkFn : Symbol(IDirectiveLinkFn, Decl(errorsWithInvokablesInUnions01.ts, 2, 1))
>TScope : Symbol(TScope, Decl(errorsWithInvokablesInUnions01.ts, 8, 28))
}
export let blah: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = (x: string) => {}
>blah : Symbol(blah, Decl(errorsWithInvokablesInUnions01.ts, 13, 10))
>IDirectiveLinkFn : Symbol(IDirectiveLinkFn, Decl(errorsWithInvokablesInUnions01.ts, 2, 1))
>ConstructableA : Symbol(ConstructableA, Decl(errorsWithInvokablesInUnions01.ts, 0, 0))
>IDirectivePrePost : Symbol(IDirectivePrePost, Decl(errorsWithInvokablesInUnions01.ts, 6, 1))
>x : Symbol(x, Decl(errorsWithInvokablesInUnions01.ts, 13, 90))
export let ctor: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = class {
>ctor : Symbol(ctor, Decl(errorsWithInvokablesInUnions01.ts, 15, 10))
>IDirectiveLinkFn : Symbol(IDirectiveLinkFn, Decl(errorsWithInvokablesInUnions01.ts, 2, 1))
>ConstructableA : Symbol(ConstructableA, Decl(errorsWithInvokablesInUnions01.ts, 0, 0))
>IDirectivePrePost : Symbol(IDirectivePrePost, Decl(errorsWithInvokablesInUnions01.ts, 6, 1))
someUnaccountedProp: any;
>someUnaccountedProp : Symbol(ctor.someUnaccountedProp, Decl(errorsWithInvokablesInUnions01.ts, 15, 96))
}

View file

@ -0,0 +1,32 @@
=== tests/cases/compiler/errorsWithInvokablesInUnions01.ts ===
interface ConstructableA {
new(): { somePropA: any };
>somePropA : any
}
interface IDirectiveLinkFn<TScope> {
(scope: TScope): void;
>scope : TScope
}
interface IDirectivePrePost<TScope> {
pre?: IDirectiveLinkFn<TScope>;
>pre : IDirectiveLinkFn<TScope>
post?: IDirectiveLinkFn<TScope>;
>post : IDirectiveLinkFn<TScope>
}
export let blah: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = (x: string) => {}
>blah : ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>
>(x: string) => {} : (x: string) => void
>x : string
export let ctor: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = class {
>ctor : ConstructableA | IDirectiveLinkFn<number> | IDirectivePrePost<number>
>class { someUnaccountedProp: any;} : typeof ctor
someUnaccountedProp: any;
>someUnaccountedProp : any
}

View file

@ -1,6 +1,6 @@
tests/cases/conformance/expressions/contextualTyping/functionExpressionContextualTyping2.ts(11,1): error TS2322: Type '(foo: number, bar: string) => boolean' is not assignable to type '((n: number, s: string) => number) | ((n: number, s: string) => string)'.
Type '(foo: number, bar: string) => boolean' is not assignable to type '(n: number, s: string) => string'.
Type 'boolean' is not assignable to type 'string'.
Type '(foo: number, bar: string) => boolean' is not assignable to type '(n: number, s: string) => number'.
Type 'boolean' is not assignable to type 'number'.
==== tests/cases/conformance/expressions/contextualTyping/functionExpressionContextualTyping2.ts (1 errors) ====
@ -17,5 +17,5 @@ tests/cases/conformance/expressions/contextualTyping/functionExpressionContextua
a1 = (foo, bar) => { return true; } // Error
~~
!!! error TS2322: Type '(foo: number, bar: string) => boolean' is not assignable to type '((n: number, s: string) => number) | ((n: number, s: string) => string)'.
!!! error TS2322: Type '(foo: number, bar: string) => boolean' is not assignable to type '(n: number, s: string) => string'.
!!! error TS2322: Type 'boolean' is not assignable to type 'string'.
!!! error TS2322: Type '(foo: number, bar: string) => boolean' is not assignable to type '(n: number, s: string) => number'.
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.

View file

@ -0,0 +1,18 @@
interface ConstructableA {
new(): { somePropA: any };
}
interface IDirectiveLinkFn<TScope> {
(scope: TScope): void;
}
interface IDirectivePrePost<TScope> {
pre?: IDirectiveLinkFn<TScope>;
post?: IDirectiveLinkFn<TScope>;
}
export let blah: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = (x: string) => {}
export let ctor: IDirectiveLinkFn<number> | ConstructableA | IDirectivePrePost<number> = class {
someUnaccountedProp: any;
}