Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

difference between `unknown` and `void`

According to this answer:

Using void instead means that forEach promises not to use the return value, so it can be called with a callback that returns any value

According to the TypeScript 3.0 release notes

... unknown is the type-safe counterpart of any. Anything is assignable to unknown, but unknown isn’t assignable to anything but itself and any ...

As much as I think about this, from these descriptions I can't find any single difference between those types.

I have also noticed that unlike unknown, when void is used as a type of a function argument, that argument can be omitted when calling the function, even though it is not marked as optional:

declare const x: (a: void) => void

x()

playground

While this behaviour is sometimes useful when working with generic code, it seems very strange. If void is supposed to only ever be used in return types, why does it have this special behaviour, unlike every other type?

like image 746
William Stanley Avatar asked Dec 31 '22 16:12

William Stanley


1 Answers

After a lengthy discussion with Aluan Haddad, my understanding is the following:

unknown is a supertype of every other type. in other languages, this is mostly what the void type is - anything can be assigned to it, but it can be used for nothing.

void is a special type. under normal circumstances, it is only a supertype of undefined and no other type, not even null.

This is what allows us to do any of the following:

const x: void = undefined;

(): void => undefined;

(): void => {};

but prevents us from doing any of:

const x: void = null;

const y: void = 5;

(): void => 5;

Unlike other types, though. void has a special behaviour if used in an output position (as part of the return type): () => T is a subtype of () => void for any T, which includes undefined, null and of course void.

This enables doing things like:

const x: () => void = () => 5

the reason for void existing and being used seems to be more historical than practical, given that it has existed before unknown and that it interacts with the type-system differently than all other types (which also causes some weird things, like Promise<number> not being a subtype of Promise<void>).

The common way to decide between these types seems to be:

  • Is it a return type of a function which I only call for side effects? Use void.
  • Is it a type (return or not) which I intend to utilise somehow, but have no guarantees about? Use unknown.
like image 80
William Stanley Avatar answered Jan 09 '23 06:01

William Stanley