Allow untyped calls on unions of untyped things (#29265)

This commit is contained in:
Wesley Wigham 2019-01-08 11:05:55 -08:00 committed by GitHub
parent 4a0bc59f77
commit 19c72c758a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 3 deletions

View file

@ -6930,7 +6930,7 @@ namespace ts {
function resolveUnionTypeMembers(type: UnionType) {
// The members and properties collections are empty for union types. To get all properties of a union
// type use getPropertiesOfType (only the language service uses this).
const callSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Call)));
const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call)));
const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct)));
const stringIndexInfo = getUnionIndexInfo(type.types, IndexKind.String);
const numberIndexInfo = getUnionIndexInfo(type.types, IndexKind.Number);
@ -20506,9 +20506,9 @@ namespace ts {
* If FuncExpr is of type Any, or of an object type that has no call or construct signatures
* but is a subtype of the Function interface, the call is an untyped function call.
*/
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number) {
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean {
// We exclude union types because we may have a union of function types that happen to have no common signatures.
return isTypeAny(funcType) || isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter ||
return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) ||
!numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType);
}

View file

@ -0,0 +1,25 @@
//// [unionOfFunctionAndSignatureIsCallable.ts]
function f1(c1: Function, c2: () => object, callable: typeof c1 | typeof c2) {
const a = c1();
const b = c2();
const c = callable();
}
function f2(fetcherParams: object | (() => object)) {
const data = typeof fetcherParams === 'function'
? fetcherParams()
: fetcherParams
}
//// [unionOfFunctionAndSignatureIsCallable.js]
function f1(c1, c2, callable) {
var a = c1();
var b = c2();
var c = callable();
}
function f2(fetcherParams) {
var data = typeof fetcherParams === 'function'
? fetcherParams()
: fetcherParams;
}

View file

@ -0,0 +1,38 @@
=== tests/cases/compiler/unionOfFunctionAndSignatureIsCallable.ts ===
function f1(c1: Function, c2: () => object, callable: typeof c1 | typeof c2) {
>f1 : Symbol(f1, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 0))
>c1 : Symbol(c1, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 12))
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>c2 : Symbol(c2, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 25))
>callable : Symbol(callable, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 43))
>c1 : Symbol(c1, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 12))
>c2 : Symbol(c2, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 25))
const a = c1();
>a : Symbol(a, Decl(unionOfFunctionAndSignatureIsCallable.ts, 1, 9))
>c1 : Symbol(c1, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 12))
const b = c2();
>b : Symbol(b, Decl(unionOfFunctionAndSignatureIsCallable.ts, 2, 9))
>c2 : Symbol(c2, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 25))
const c = callable();
>c : Symbol(c, Decl(unionOfFunctionAndSignatureIsCallable.ts, 3, 9))
>callable : Symbol(callable, Decl(unionOfFunctionAndSignatureIsCallable.ts, 0, 43))
}
function f2(fetcherParams: object | (() => object)) {
>f2 : Symbol(f2, Decl(unionOfFunctionAndSignatureIsCallable.ts, 4, 1))
>fetcherParams : Symbol(fetcherParams, Decl(unionOfFunctionAndSignatureIsCallable.ts, 6, 12))
const data = typeof fetcherParams === 'function'
>data : Symbol(data, Decl(unionOfFunctionAndSignatureIsCallable.ts, 7, 9))
>fetcherParams : Symbol(fetcherParams, Decl(unionOfFunctionAndSignatureIsCallable.ts, 6, 12))
? fetcherParams()
>fetcherParams : Symbol(fetcherParams, Decl(unionOfFunctionAndSignatureIsCallable.ts, 6, 12))
: fetcherParams
>fetcherParams : Symbol(fetcherParams, Decl(unionOfFunctionAndSignatureIsCallable.ts, 6, 12))
}

View file

@ -0,0 +1,45 @@
=== tests/cases/compiler/unionOfFunctionAndSignatureIsCallable.ts ===
function f1(c1: Function, c2: () => object, callable: typeof c1 | typeof c2) {
>f1 : (c1: Function, c2: () => object, callable: Function | (() => object)) => void
>c1 : Function
>c2 : () => object
>callable : Function | (() => object)
>c1 : Function
>c2 : () => object
const a = c1();
>a : any
>c1() : any
>c1 : Function
const b = c2();
>b : object
>c2() : object
>c2 : () => object
const c = callable();
>c : any
>callable() : any
>callable : Function | (() => object)
}
function f2(fetcherParams: object | (() => object)) {
>f2 : (fetcherParams: object | (() => object)) => void
>fetcherParams : object | (() => object)
const data = typeof fetcherParams === 'function'
>data : any
>typeof fetcherParams === 'function' ? fetcherParams() : fetcherParams : any
>typeof fetcherParams === 'function' : boolean
>typeof fetcherParams : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
>fetcherParams : object | (() => object)
>'function' : "function"
? fetcherParams()
>fetcherParams() : any
>fetcherParams : Function | (() => object)
: fetcherParams
>fetcherParams : object
}

View file

@ -0,0 +1,11 @@
function f1(c1: Function, c2: () => object, callable: typeof c1 | typeof c2) {
const a = c1();
const b = c2();
const c = callable();
}
function f2(fetcherParams: object | (() => object)) {
const data = typeof fetcherParams === 'function'
? fetcherParams()
: fetcherParams
}