I am working on a JavaScript function and I want to define a type signature for it.
function wrapInFunction(value) {
if (typeof value === 'function') {
return value;
} else {
return () => value;
}
}
This function takes an input that may or may not be a function. If the input is not a function, it transforms it into one in a simple manner. Initially, I attempted to do this:
function wrapInFunction<A extends Array<unknown>, B>(value: B | ((...a: A) => B)): (...a: A) => B {
if (typeof value === 'function') {
return value;
} else {
return () => value;
}
}
However, TypeScript flagged an issue where B & Function
might cause a type error if nonempty in the first case.
src/op.ts:360:5 - error TS2322: Type '((...a: A) => B) | (B & Function)' is not assignable to type '(...a: A) => B'.
Type 'B & Function' is not assignable to type '(...a: A) => B'.
Type 'Function' provides no match for the signature '(...a: A): B'.
360 return value;
To address this concern, I attempted to use the Exclude
utility
function wrapInFunction<A extends Array<unknown>, B>(value: Exclude<B, Function> | ((...a: A) => B)): (...a: A) => B {
if (typeof value === 'function') {
return value;
} else {
return () => value;
}
}
Despite this adjustment, the error persisted:
src/op.ts:360:5 - error TS2322: Type '((...a: A) => B) | (Exclude<B, Function> & Function)' is not assignable to type '(...a: A) => B'.
Type 'Exclude<B, Function> & Function' is not assignable to type '(...a: A) => B'.
Type 'Function' provides no match for the signature '(...a: A): B'.
360 return value;
In my understanding,
Exclude<B, Function> & Function
should result in an empty type. If I can demonstrate to TypeScript that this scenario is impossible, then the type signature should work properly.
Is there a way to prove that
Exclude<B, Function> & Function
is always empty? Or perhaps, is there a better approach to defining the type signature for my wrapInFunction
function?
Side Note: When calling this function within my program, I will be using instances of B
that are clearly not functions, such as class types and primitives like number
. Therefore, for my current use cases, Exclude<B, Function>
and B
should have identical members. However, it would be beneficial to demonstrate this to the type checker without relying on manual casting with value as (...a: A) => B
.