Search Terms
calling union types
Suggestion
Give TS the ability to infer that calling a value that is typed with a union of functions of differing call signatures is valid when a type guard that narrows the union of functions to a function, or a new union of functions with identical signatures, is used in a conditional expression to select arguments with the correct type to be passed.
Use Cases
Creating a TypedArray using a variable TypedArrayConstructor:
declare function isBigInt64ArrayConstructor(x: any): x is BigInt64ArrayConstructor
let x: Int16ArrayConstructor | Int32ArrayConstructor | BigInt64ArrayConstructor
// From this
function doStuff(y: number) {
switch (y) {
case 0:
if (!isBigInt64ArrayConstructor(x))
return x.of(0, 1)
return x.of(0n, 1n)
case 1:
if (!isBigInt64ArrayConstructor(x))
return x.of(1, 0)
return x.of(1n, 0n)
case 2:
if (!isBigInt64ArrayConstructor(x))
return x.of(0, 1, y)
return x.of(0n, 1n, BigInt(y))
}
}
// To this
function cleanerDoStuff(y: number) {
const [ZERO, ONE, WHY] = isBigInt64ArrayConstructor(x)
? [0n, 1n, BigInt(y)]
: [0, 1, y]
switch(y) {
case 0:
return x.of(ZERO, ONE)
case 1:
return x.of(ONE, ZERO)
case 2:
return x.of(ZERO, ONE, WHY)
}
}
Examples
This does not work as of TS 3.7.5:
interface iTakeNumbers {
(x: number)
takesBigInts: false
}
interface iTakeBigInts {
(x: bigint)
takesBigInts: true
}
type iTakeNumbersOrBigInts = iTakeNumbers | iTakeBigInts
let x: iTakeNumbersOrBigInts
function doesTakeNumbers(x: iTakeNumbersOrBigInts): x is iTakeNumbers {
return !x.takesBigInts
}
const ZERO = doesTakeNumbers(x) ? 0 : 0n
if (doesTakeNumbers(x)) {
// Works as TS narrows x to iTakeNumbers
x(0)
/**
* Case 1:
* Argument of type 'bigint | 0' is not assignable to parameter of type 'number'.
* Type 'bigint' is not assignable to type 'number'. ts(2345)
*/
x(ZERO)
} else {
// Works as TS narrows x to iTakeBigInts
x(0n)
/**
* Case 2:
* Argument of type 'bigint | 0' is not assignable to parameter of type 'number'.
* Type '0' is not assignable to type 'number'. ts(2345)
*/
x(ZERO)
}
/**
* Case 3:
* Argument of type 'bigint | 0' is not assignable to parameter of type 'never'.
* Type 'bigint' is not assignable to type 'never'. ts(2345)
*/
x(ZERO)
In the 1st and 2nd case, ZERO should be narrowed down to the appropriate type as the compiler should be able to infer that doesTakeNumbers is pure and thus defining ZERO with a conditional expression at the top level is equivalent to defining ZERO inside both the if and else blocks with the appropriate 0 for each respectively.
In the 3rd case, the compiler should be able to infer that ZERO will be the correct type for use as the argument to x during runtime since ZERO should be conditionally typed correctly based on the result of the type guard doesTakeNumbers called with x. Maybe this could be done with an extension to the existing conditional types where the compiler could infer the type of ZERO to be a conditional type instead of a bigint | number,
Checklist
My suggestion meets these guidelines:
Search Terms
calling union types
Suggestion
Give TS the ability to infer that calling a value that is typed with a union of functions of differing call signatures is valid when a type guard that narrows the union of functions to a function, or a new union of functions with identical signatures, is used in a conditional expression to select arguments with the correct type to be passed.
Use Cases
Creating a TypedArray using a variable TypedArrayConstructor:
Examples
This does not work as of TS 3.7.5:
In the 1st and 2nd case,
ZEROshould be narrowed down to the appropriate type as the compiler should be able to infer thatdoesTakeNumbersis pure and thus definingZEROwith a conditional expression at the top level is equivalent to definingZEROinside both theifandelseblocks with the appropriate0for each respectively.In the 3rd case, the compiler should be able to infer that
ZEROwill be the correct type for use as the argument toxduring runtime sinceZEROshould be conditionally typed correctly based on the result of the type guarddoesTakeNumberscalled withx. Maybe this could be done with an extension to the existing conditional types where the compiler could infer the type ofZEROto be a conditional type instead of abigint | number,Checklist
My suggestion meets these guidelines: