Last active
September 5, 2022 10:57
-
-
Save betafcc/827814d341522f8f74cc4b0df1d1e1a1 to your computer and use it in GitHub Desktop.
Type-Level FizzBuzz in Typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Iterator approach, seems to be good up until ~850 | |
type Result = Take<100, FizzBuzzIterator[1]> | |
// ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz", ...] | |
export type FizzBuzzIterator< | |
S extends Record<any, any> = { 3: []; 5: []; i: [] }, | |
R extends string = `${S[3]["length"] extends 3 ? "Fizz" : ""}${S[5]["length"] extends 5 ? "Buzz" : ""}` | |
> = [ | |
R extends "" ? `${S["i"]["length"]}` : R, | |
FizzBuzzIterator<{ | |
3: S[3]["length"] extends 3 ? [1] : [...S[3], 1] | |
5: S[5]["length"] extends 5 ? [1] : [...S[5], 1] | |
i: [...S["i"], 1] | |
}> | |
] | |
type Take<N extends number, Cons extends [any, any], Acc extends any[] = []> | |
= Acc["length"] extends N ? Acc : Take<N, Cons[1], [...Acc, Cons[0]]> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Normal recursive approach, seems to be good up until ~850 | |
type Result = FizzBuzzRange<1, 101> | |
// ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz", ...] | |
export type FizzBuzzRange<A extends number, B extends number, Acc extends any[] = []> | |
= A extends B ? Acc : FizzBuzzRange<Add<A, 1>, B, [...Acc, FizzBuzz<A>]> | |
export type FizzBuzz< | |
X extends number, | |
S extends string = `${Div<X, 3> extends true ? "Fizz" : ""}${Div<X, 5> extends true ? "Buzz" : ""}` | |
> = S extends "" ? `${X}` : S | |
type Div<A extends number, B extends number, Acc extends number = B> | |
= A extends Acc ? true : Lt<A, Acc> extends true ? false : Div<A, B, Add<Acc, B>> | |
type Add<A extends number, B extends number> = Extract<[...Range<A>, ...Range<B>]["length"], number> | |
type Range<N extends number, Acc extends number[] = []> | |
= Acc["length"] extends N ? Acc : Range<N, [...Acc, Acc["length"]]> | |
type Lt<A extends number, B extends number, R extends number[] = Range<B>> = A extends R[number] ? true : false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment