Home > Software design >  Why are type annotations different on functions and variables?
Why are type annotations different on functions and variables?

Time:04-22

I think the following code is assigning type string to type unknown, but compiler give an opposite error message.

let y: (arg: unknown) => any;
let y1: unknown

y = (s: string) => s // Type 'unknown' is not assignable to type 'string'.ts(2322)
y1 = "y1"

CodePudding user response:

Variance!

The definition of y accepts any argument, including let's say 1. But the implementation only works on string, so y(1) will be an error.

y1 is different: it can be any value, including 1, y1 and (s: string) => s, and it's up to whoever is using it to consume strings, integers and functions.

See also this excellent answer.

CodePudding user response:

Because functions can be called from other places.

Take this, for example:

let y: (arg: unknown) => any = (arg) => arg
y(123) // fine

This is a perfectly acceptable invocation of y(). unknown can be anything, so passing a number there is fine.

Now do this:

let y: (arg: unknown) => any = (arg) => arg
y = (s: string) => s.toUpperCase()
y(123) // crash

number would no longer be a valid argument for y() because (s: string) => any would let the function assume that the argument was a string, but no guarantee can be made here.

This means that the argument type in the function type unknown must be assignable to the argument type in what you are assigning string (because you can still call the function with an unknown argument). And unknown is not assignable to string.

  • Related