Skip to content

Allow untyped calls on unions of untyped things #29265

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

Merged
merged 1 commit into from
Jan 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
25 changes: 25 additions & 0 deletions tests/baselines/reference/unionOfFunctionAndSignatureIsCallable.js
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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))
}

Original file line number Diff line number Diff line change
@@ -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
}

11 changes: 11 additions & 0 deletions tests/cases/compiler/unionOfFunctionAndSignatureIsCallable.ts
Original file line number Diff line number Diff line change
@@ -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
}