I was trying to use (infer R)[] for never and any types to unpack arrays.
type UnpackArrayType<T> = [T] extends [(infer R)[]] ? R : false;
But the result was unexpectable: Typescript neither cast false from "else" (non-array condition) nor detect inferred type R.
demo link
type UnpackArrayType<T> = [T] extends [(infer R)[]] ? R : false; // false type used as non-array-marker
type UA<T> = UnpackArrayType<T>; // just alias
type TypeTesting = {
"never": UA<never>, // unknown - incorrect
"never[]": UA<never[]>, // never - correct
"any": UA<any>, // unknown - incorrect
"any[]": UA<any[]>, // any - correct
"unknown": UA<unknown>, // false - correct
"unknown[]": UA<unknown[]>, // unknown - correct
"null": UA<null>, // false - correct
"null[]": UA<null[]>, // null - correct
"undefined": UA<undefined>, // false - correct
"undefined[]": UA<undefined[]>, // undefined - correct
"number": UA<number>, // false - correct
"number[]": UA<number[]>, // number - correct
}
Why any and never types unpacking as unknown?
extends tests relationships between types and then attempts to extract the inferred location.
any and never both have the property that they are subtypes of any other type (any is even stranger as it is also a base type of any other type). So asking the question never extends T or any extends T will return true for any type T.
After the extends question is answered then can we consider the inference question and since there is no good way to extract R in [(infer R)[]] from any or never you end up with unknown.
You could special case these two universal types subtype:
type UnpackArrayType<T> =
[T] extends [never] ? false: // nothing extends never except never itslef
[T & 1] extends [T & 2]? false : // T & 1 extends T & 2 will only be true if T is any and the & 1 and & 2 get absorbed into any
[T] extends [(infer R)[]] ? R : false; // false type used as non-array-marker
type UA<T> = UnpackArrayType<T>; // just alias
type TypeTesting = {
"never": UA<never>, // false - correct
"never[]": UA<never[]>, // never - correct
"any": UA<any>, // false - correct
"any[]": UA<any[]>, // any - correct
"unknown": UA<unknown>, // false - correct
"unknown[]": UA<unknown[]>, // unknown - correct
"null": UA<null>, // false - correct
"null[]": UA<null[]>, // null - correct
"undefined": UA<undefined>, // false - correct
"undefined[]": UA<undefined[]>, // undefined - correct
"number": UA<number>, // false - correct
"number[]": UA<number[]>, // number - correct
}
Playground Link
Note: To extract the element type from a type known to be an array you can also use T[number]
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