Take this code: playground here
declare const slice: Record<string, never> | string[];
slice.forEach(foo => console.log(foo))
Slice could be a Record<string, never>
, which as I understand it, is basically an empty object. So why does TS allow me to call .forEach
on it? It seems like at runtime this could result in a forEach is not a function
error.
Consider this example:
declare let slice: Record<string, never> | string[];
Union type returns you most common safe type. See docs
TypeScript will only allow an operation if it is valid for every member of the union. For example, if you have the union string | number, you can’t use methods that are only available on string.
Hence, TS allows you to use methods from string[]
only because string
in Record
represents more general type. It means that string
in Record
allows you to use any string as a key, whereas string[]
allows you to use only array methods. So, forEach
method is safe to use for both string[]
and Record<string, never>
.
As for the value. never
is assignable to every type in typescript, whereas every type in typescript is not assignable to never
. See assignability table in docs
declare let never: never;
declare let fn: () => void
never = fn // error
fn = never // ok
Hence, never
is always clashed in the union with other types. See this:
type Union = never | string
Here, in PR you will find an explanation of this behavior:
Because
never
is a subtype of every type, it is always omitted from union types and it is ignored in function return type inference as long as there are other types being returned.
So, if you have a union of Array.prototype.method with never
- {forEach:(...args:any)=>any} | never
, it always ommits never
.
This is why you are not getting an error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With