Skip to content

Instantly share code, notes, and snippets.

@vezaynk
Created July 12, 2022 06:24
Show Gist options
  • Save vezaynk/310b14006af4531bb827e84111a3db15 to your computer and use it in GitHub Desktop.
Save vezaynk/310b14006af4531bb827e84111a3db15 to your computer and use it in GitHub Desktop.
interface StringDigitToNumber {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
}
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0';
type NumericStringAsDigitArray<T extends `${Digit}${string}`> =
T extends `${infer L extends Digit}${infer F extends string}` ?
F extends `${Digit}${string}` ? [StringDigitToNumber[L], ...NumericStringAsDigitArray<F>] : [StringDigitToNumber[L]] : never;
type Flatten<T extends any[]> =
T extends [infer First, ...infer Rest]
? First extends any[]
? Flatten<[...First, ...Rest]>
: [First, ...Flatten<Rest>]
: []
type OneTwoThree = NumericStringAsDigitArray<"123">;
// ^? type OneTwoThree = [1, 2, 3]
@vezaynk
Copy link
Author

vezaynk commented Jul 12, 2022

Going to bed.

Using others' solutions, we can join and convert the result to a number. A function MinusOne<> generic is waiting:

interface StringDigitToNumber {
  '0': 0,
  '1': 1,
  '2': 2,
  '3': 3,
  '4': 4,
  '5': 5,
  '6': 6,
  '7': 7,
  '8': 8,
  '9': 9,
}
interface PreviousNumber {
  '0': '9',
  '1': '0',
  '2': '1',
  '3': '2',
  '4': '3',
  '5': '4',
  '6': '5',
  '7': '6',
  '8': '7',
  '9': '8',
}
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0';


type NumericStringAsDigitArray<T extends `${Digit}${string}`> = 
T extends `${infer L extends Digit}${infer F extends string}` ? 
    F extends `${Digit}${string}` ? [L, ...NumericStringAsDigitArray<F>] : [L] : never;

type OneTwoThree = NumericStringAsDigitArray<"123">;
//    ^?

type MinusOneArray<T extends Digit[]> = CleanLeadingZero<
T extends [...infer R extends Digit[], infer L extends Digit] ? 
    L extends "0" ? 
        [...MinusOneArray<R>, PreviousNumber[L]]
    : [...R, PreviousNumber[L]]
: never>;

type CleanLeadingZero<T extends Digit[]> = T extends ['0', ...infer R extends Digit[]] ? R : T;
type Test1 = MinusOneArray<["1", "2", "3"]>;
//    ^?
type Test2 = MinusOneArray<["1", "0", "0"]>;
//    ^?
type Join<
  T extends any[], 
  U extends string | number,
  R extends string = ''
> = 
  T extends [infer F,...infer L]?
    L['length'] extends 0?
      `${R extends ''?'':`${R}${U}`}${F&string}`
      :Join<L,U,`${R extends ''?'':`${R}${U}`}${F&string}`>
  :R

  type Test3 = Join<Test2, ''>;

  type Mul10<I extends ReadonlyArray<any> = []> = [...I, ...I, ...I, ...I, ...I, ...I, ...I, ...I, ...I, ...I]

type Dec2Arr = {
  '0': [],
  '1': [1],
  '2': [1, 1],
  '3': [1, 1, 1],
  '4': [1, 1, 1, 1],
  '5': [1, 1, 1, 1, 1],
  '6': [1, 1, 1, 1, 1, 1],
  '7': [1, 1, 1, 1, 1, 1, 1],
  '8': [1, 1, 1, 1, 1, 1, 1, 1],
  '9': [1, 1, 1, 1, 1, 1, 1, 1, 1],
}

type DecChar = keyof Dec2Arr

type Str2Arr<S extends string, Remain extends ReadonlyArray<any> = []> =
  S extends DecChar ? [...Mul10<Remain>, ...Dec2Arr[S]] :
  S extends `${infer Leading}${infer Trailing}` ? (
    Leading extends DecChar
    ? Str2Arr<Trailing, [...Mul10<Remain>, ...Dec2Arr[Leading]]> : []
  ) : []

type ToNumber<S extends string> = Str2Arr<S>['length']

type result = ToNumber<Join<MinusOneArray<NumericStringAsDigitArray<'10000'>>,''>>; // 9999

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment