Why doesn't this work?
const x: unknown[] = ['x', 32, true]; // OK
const y: (...args: unknown[]) => unknown = (xx: number) => {}; // ERROR
// Type '(xx: number) => void' is not assignable to type '(...args: unknown[]) => unknown'.
// Types of parameters 'xx' and 'args' are incompatible.
// Type 'unknown' is not assignable to type 'number'. ts(2322)
My goal is to make sure that y is any runnable function. I was trying not to use any.
Hope to improve my understanding of how unknown works in this case.
CodePudding user response:
Function types are contravariant in their parameter types; see Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript for more details. Contravariance means the direction of assignability flips; if T is assignable to U, then (...u: U) => void is assignable to (...t: T) => void and not vice versa. This is necessary for type safety. Picture the direction of data flow: if you want fruit then I can give you an apple, but if you want something that will eat all your fruit I can't give you something that eats only apples.
The function type (xx: number) => void is equivalent to (...args: [number]) => void, and you cannot assign that to (...args: unknown[]) => void. Yes, [number] is assignable to unknown[], but that's not the direction we care about. Your assignment is therefore unsafe. If this worked:
const y: (...args: unknown[]) => unknown =
(xx: number) => xx.toFixed(); // should this be allowed?
Then you'd be able to call y() with any set of arguments you wanted without a compiler error, but hit a runtime error:
y("x", 32, true); // no compiler error
// 