Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@bingo347
Last active August 1, 2021 16:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bingo347/00652993abf31702cdbfb6c109af5fbf to your computer and use it in GitHub Desktop.
Save bingo347/00652993abf31702cdbfb6c109af5fbf to your computer and use it in GitHub Desktop.
Typescript arithmetic example
type Computable
= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
| 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19
| 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29
| 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39
| 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49
| 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59
| 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69
| 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79
| 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89
| 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99;
type NextComputable<N extends Computable> = {
0: 1; 1: 2; 2: 3; 3: 4; 4: 5; 5: 6; 6: 7; 7: 8; 8: 9; 9: 10;
10: 11; 11: 12; 12: 13; 13: 14; 14: 15; 15: 16; 16: 17; 17: 18; 18: 19; 19: 20;
20: 21; 21: 22; 22: 23; 23: 24; 24: 25; 25: 26; 26: 27; 27: 28; 28: 29; 29: 30;
30: 31; 31: 32; 32: 33; 33: 34; 34: 35; 35: 36; 36: 37; 37: 38; 38: 39; 39: 40;
40: 41; 41: 42; 42: 43; 43: 44; 44: 45; 45: 46; 46: 47; 47: 48; 48: 49; 49: 50;
50: 51; 51: 52; 52: 53; 53: 54; 54: 55; 55: 56; 56: 57; 57: 58; 58: 59; 59: 60;
60: 61; 61: 62; 62: 63; 63: 64; 64: 65; 65: 66; 66: 67; 67: 68; 68: 69; 69: 70;
70: 71; 71: 72; 72: 73; 73: 74; 74: 75; 75: 76; 76: 77; 77: 78; 78: 79; 79: 80;
80: 81; 81: 82; 82: 83; 83: 84; 84: 85; 85: 86; 86: 87; 87: 88; 88: 89; 89: 90;
90: 91; 91: 92; 92: 93; 93: 94; 94: 95; 95: 96; 96: 97; 97: 98; 98: 99; 99:never;
}[N];
type PrevComputable<N extends Computable> = {
0:never; 1: 0; 2: 1; 3: 2; 4: 3; 5: 4; 6: 5; 7: 6; 8: 7; 9: 8;
10: 9; 11: 10; 12: 11; 13: 12; 14: 13; 15: 14; 16: 15; 17: 16; 18: 17; 19: 18;
20: 19; 21: 20; 22: 21; 23: 22; 24: 23; 25: 24; 26: 25; 27: 26; 28: 27; 29: 28;
30: 29; 31: 30; 32: 31; 33: 32; 34: 33; 35: 34; 36: 35; 37: 36; 38: 37; 39: 38;
40: 39; 41: 40; 42: 41; 43: 42; 44: 43; 45: 44; 46: 45; 47: 46; 48: 47; 49: 48;
50: 49; 51: 50; 52: 51; 53: 52; 54: 53; 55: 54; 56: 55; 57: 56; 58: 57; 59: 58;
60: 59; 61: 60; 62: 61; 63: 62; 64: 63; 65: 64; 66: 65; 67: 66; 68: 67; 69: 68;
70: 69; 71: 70; 72: 71; 73: 72; 74: 73; 75: 74; 76: 75; 77: 76; 78: 77; 79: 78;
80: 79; 81: 80; 82: 81; 83: 82; 84: 83; 85: 84; 86: 85; 87: 86; 88: 87; 89: 88;
90: 89; 91: 90; 92: 91; 93: 92; 94: 93; 95: 94; 96: 95; 97: 96; 98: 97; 99: 98;
}[N];
type AddComputableBasis<N extends Computable> = {
[I in Computable]: I extends 0 ? N : NextComputable<AddComputableBasis<N>[PrevComputable<I>]>;
};
type SubComputableBasis<N extends Computable> = {
[I in Computable]: I extends 0 ? N : PrevComputable<SubComputableBasis<N>[PrevComputable<I>]>;
};
type AddComputable<N extends Computable, M extends Computable> = AddComputableBasis<N>[M];
type SubComputable<N extends Computable, M extends Computable> = SubComputableBasis<N>[M];
// examples:
const _add_7_5_ok: AddComputable<7, 5> = 12; // ok
const _add_7_5_err: AddComputable<7, 5> = 11; // err
const _sub_7_5_ok: SubComputable<7, 5> = 2; // ok
const _sub_7_5_err: SubComputable<7, 5> = 3; // err
type Test = Sum<2143, 174>;
const test: Test = '2317';
const testError: Test = '2318';
type Basis = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
type Digit = Basis[number];
type Stringify<N extends number> = `${N}`;
type DigitArray = Stringify<Digit>[];
type DigitMap = {
[D in Digit as Stringify<D>]: D;
};
type SplitNumber<S extends `${number}`> = S extends Stringify<Digit>
? [S]
: S extends `${infer D}${infer Tail}`
? [...SplitNumber<Tail & `${number}`>, D & Stringify<Digit>]
: never;
type SplitArray<A extends DigitArray, End extends DigitArray = ['0']> = A extends [infer D, ...infer Tail]
? [DigitMap[D & Stringify<Digit>], Tail]
: [0, End];
type RevertedBasis = {
[D in Digit as Basis[D]]: D;
};
type DigitSums = {
[D1 in Digit]: {
[D2 in Digit]: D2 extends 0
? {
digit: D1;
shift: false;
}
: {
digit: Basis[DigitSums[D1][RevertedBasis[D2]]['digit']];
shift: DigitSums[D1][RevertedBasis[D2]]['shift'] extends true
? true
: DigitSums[D1][RevertedBasis[D2]]['digit'] extends 9
? true
: false;
};
};
};
type SumDigits<
D1 extends Digit,
D2 extends Digit,
Shift extends boolean,
> = Shift extends false
? DigitSums[D1][D2]
: D1 extends 9
? {
digit: D2;
shift: true;
}
: DigitSums[Basis[D1]][D2]
type SumCalculatorInternal<
D1 extends DigitArray,
D2 extends DigitArray,
R extends DigitArray,
Shift extends boolean,
> = D1 extends []
? [...R, ...D2]
: D2 extends []
? [...R, ...D1]
: SumCalculatorInternal<
SplitArray<D1>[1],
SplitArray<D2>[1],
[...R, Stringify<SumDigits<SplitArray<D1>[0], SplitArray<D2>[0], Shift>['digit']>],
SumDigits<SplitArray<D1>[0], SplitArray<D2>[0], Shift>['shift']
>;
type CollectResult<D extends DigitArray, R extends string = ''> = D extends []
? R
: CollectResult<SplitArray<D, []>[1], `${SplitArray<D>[0]}${R}`>;
type SumCalculator<D1 extends number, D2 extends number> = SumCalculatorInternal<
SplitNumber<Stringify<D1>>,
SplitNumber<Stringify<D2>>,
[],
false
>
type Sum<D1 extends number, D2 extends number> = CollectResult<SumCalculator<D1, D2> extends DigitArray
? SumCalculator<D1, D2>
: never>;
@bingo347
Copy link
Author

bingo347 commented Jul 14, 2021

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