Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Explanation of " R['length'] extends N " syntax in TypeScript

new to TypeScript, was searching for a way to define a fixed size array and came across this:

type Tuple<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;

type Tuple9<T> = Tuple<T, 9>;
type Board9x9<P> = Tuple9<Tuple9<P>>;

…which obtains the desired result using recursive conditional types.
I was trying to understand the syntax that is being used, and I couldn’t really understand what is happening behind the scenes particularly in this point: R['length'] extends N.

I understood that it checks if the array is of the desired length and if not it’ll recursively call _TupleOf with an extra element until that condition becomes true. but why is that happening?
I searched for answers but couldn’t really find anything useful.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Does R['length'] return the actual length as a number if it is applied to a type? And why extends seems to behaves like a == operator in this case?

I’ve also tried double-checking if it behaves as i understood in this playground (you can hover over b and c to check the types) and it seems it does, still can’t understand why tho.

Any link or explanation? thanks in advance!

>Solution :

It’s because:

  1. The type of the length property of a tuple is a literal numeric type equal to the number of elements in the tuple. So not just a number, but a specific number (like 42).
  2. Numeric literal types extend number. (Hmmm… I’m not sure why I mentioned this, but it’s in the examples below so I’ll keep it.)
  3. A numeric literal type only "extends" (is the same as or a subtype of) itself.
type TwoThings = [string, string];
type TwoThingsLength = TwoThings["length"];
//   ^? −−− type TwoThingsLength = 2

type IsNumber<T> = T extends number ? true : false;
type A = IsNumber<27>;
//   ^? −−− type A = true
type B = IsNumber<"example">;
//   ^? −−− type B = false

type IsThisNumber<T, Num> = T extends Num ? true : false;
type C = IsThisNumber<27, 27>;
//   ^? −−− type C = true
type D = IsThisNumber<27, 42>;
//   ^? −−− type D = false

// Which leads us to
type E = IsThisNumber<TwoThingsLength, 2>; // true, they're the same literal number
//   ^? −−− type E = true
type F = IsThisNumber<TwoThingsLength, 3>; // false, they aren't
//   ^? −−− type F = false

Playground link

So R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]> works by:

  • If R['length'] is the same as the target length N, evaluate to the R type itself
  • If not, create a new tuple type which has element T plus all of the previous elements (...R) — e.g., add one — and recurse
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading