Home > database >  TypeScript `unknown` doesn't allow non-unknown types in function parameters
TypeScript `unknown` doesn't allow non-unknown types in function parameters

Time:12-31

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
//            
  • Related