Avoid usage of type any, really
This is only a side remark that has nothing to do with your algorithmic ideas. You defined
type BuildTuple<L extends number, T extends any[] = []> =T extends { length: L }? T: BuildTuple<L, [...T, any]>;
I strongly recommend to replace any
by unknown
. I have just learned the lesson that I describe here by myself. I had read before this article but it didn’t mention the, to my mind, most important counterargument against the usage of any
: Besides it being a top type (as to be expected) it is also a bottom type and that came as a big surprise to me. I stumbled over it in connection with your EQ
type
type EQ<A, B> =A extends B? (B extends A ? true : false): false;
First of all this should be changed to
type EQ<A, B> =
[A] extends [B]
? ([B] extends [A] ? true : false)
: false;
to prevent unintended distribution as I have argued for in my previous comment “Your EQ type looks innocent but is really insidious” (I don’t know how to link it here). As for the any
problem, have a look at this
const test: EQ<boolean, any> = true; // !!!
What? boolean
and any
are equivalent? The reason is that
const testAnyExtends: (any extends boolean ? true : false) = true;
any
is simultaneously a bottom type, thus extending anything, exactly as the “official” bottom type never
does. I understand now why Microsoft implemented it this way, viz. for to use any
as a vehicle to switch type checking off. Nevertheless, I was completely unaware of this consequence and I guess, I am not the only one. The lesson I took is: Use unknown
instead of any
since the former is just a top not simultaneously a bottom type. The difference is demonstrated as well here
let testAny: any = 'hello';
let testUnknown: unknown = 'hello';
let x: number;
x = testAny; // !!! this assignment is admissible !!!
x = testUnknown; // this induces a compiler error as it should be
After changing any
to unknown
in my arithmetic implementation (see my subsequent comment that will follow) some cases of evaluating to wrong branches in conditional types within my type CheckedNaturalNumber
vanished. Thus, it is not just an academic problem. It had real consequences in my code. So, I recommend to change your BuildTuple
type into
type BuildTuple<L extends number, T extends unknown[] = []> =T extends { length: L }? T: BuildTuple<L, [...T, unknown]>;