Binary to Decimal

Challenge

Implement BinaryToDecimal<S> which takes an exact string type S consisting 0 and 1 and returns an exact number type corresponding with S when S is regarded as a binary. You can assume that the length of S is equal to or less than 8 and S is not empty.

type Res1 = BinaryToDecimal<"10">; // expected to be 2
type Res2 = BinaryToDecimal<"0011">; // expected to be 3

Solution

Da man bei der Umwandlung von binär nach Dezimal von hinten anfängt zu zahlen, ist es sinnvoll, einen Hilfstyp zu definieren, welcher die Zeichenkette umdreht:

// 0011 => 1100
type ReverseString<
  T extends string,
  R extends string = ""
> = T extends `${infer F}${infer Rest}` ? ReverseString<Rest, `${F}${R}`> : R;

Nun können wir mittels infer wieder über die Zeichenkette laufen, und das erste Zeichen in die Typvariable H extrahieren. Ist H eine 1, so erhöhen wir den Akkumulator Acc um BinSum. BinSum speichert die aktuelle Dezimalzahl zum Index ab (z.B. Index 3 → [1,1,1,1], Länge ist 4):

// Beispiel: 0011
// Start) BinSum [1], Acc []
// 1.) BinSum [1], Acc [1]
// 2.) BinSum [1,1], Acc [1,1,1]
// 3.) BinSum [1,1,1,1], Acc [1,1,1]
// 4.) BinSum [1,1,1,1,1,1,1,1], Acc [1,1,1]

type BinaryToDecimal<
  S extends string,
  T = ReverseString<S>,
  BinSum extends 1[] = [1],
  Acc extends 1[] = []
> = T extends `${infer H extends number}${infer R}`
  ? H extends 1
    ? BinaryToDecimal<S, R, [...BinSum, ...BinSum], [...Acc, ...BinSum]>
    : BinaryToDecimal<S, R, [...BinSum, ...BinSum], Acc>
  : Acc["length"];

References