`Pick`

itself.
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00004-easy-pick/README.md

Given the following TypeScript:

`interface Todo {`

title: string

description: string

completed: boolean

}

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

Given the interface `Todo`

above, we need to create a generic type `MyPick`

that takes the type (`Todo`

) and a union of the properties that we wish to pick from it. The base code would look something like:

`type MyPick<T, K> = ?`

If we were creating a function in JavaScript to do a similar job, we'd want to loop over everything in `K`

and construct a new object with each entry from `K`

as a key. We'd set that key value equal to `T[i]`

to reference the original value of T for that key.

We can do something similar in TypeScript types with mapped types. The syntax for a mapped type is:

`type MyPick<T, K> = {`

[Property in K]: T[Property]

}

Where property is bound to each entry in our `K`

type union.

The above creates a new type from the existing type `T`

, with only the keys from `K`

in it, as it loops over the entries in `K`

only. However it doesn't work as TypeScript has no guarantee that the type K is a union type. For example:

`MyPick<Todo, number>`

Would not through any TypeScript errors as both `T`

and `K`

are types, `Todo`

and `number`

respectively. Clearly we need to restrict the type of K to be a union type of keys that exist on T.

`type MyPick<T, K extends keyof T> = {`

[Property in K]: T[Property]

}

This means that even if K is a union, if it includes properties that do not exist on T, it will result in a compiler error.

]]>`Readonly`

itself.
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00007-easy-readonly/README.md

Given the following TypeScript:

`interface Todo {`

title: string

description: string

}

const todo: MyReadonly<Todo> = {

title: "Hey",

description: "foobar"

}

We need to create a new type called `MyReadonly`

that will result in the following operations failing,

`todo.title = "Hello" // Error: cannot reassign a readonly property`

todo.description = "barFoo" // Error: cannot reassign a readonly property

This means we need to create a generic type that accepts a type as a parameter, and returns a new type with the `readonly`

property set for each property in that type.

`type MyReadonly<T> = ?`

We need to create a new type based off an existing type, this means we need to use mapped types in TypeScript.

The basic syntax for a mapped type is:

`type MyReadonly<T> = {`

[Property in keyof T]: T[Property]

}

Here we use `keyof T`

to generate a union type of all the properties of T, which we then use to iterate over and generate a new type from. The type that the above returns is exactly the same as the type `T`

passed in.

Mapped types allow you to add or remove modifiers when you create new types. These modifiers are `?`

to control optionality and `readonly`

to control mutability.

You can add them with `+`

and remove them with `-`

.

Therefore we can add the `readonly`

by prefixing each entry in our new type with the `+readonly`

modifier.

`type MyReadonly<T> = {`

+readonly [Property in keyof T]: T[Property]

}

However, when adding modifiers, the `+`

is optional, so we can simplify this type to:

`type MyReadonly<T> = {`

readonly [Property in keyof T]: T[Property]

}

]]>
`Exclude`

The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00043-easy-exclude/README.md

For example, given the following cases, our MyExclude type should return the type shown in the comments:

` MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'`

MyExclude<'a' | 'b' | 'c', 'a' | 'b'> // 'c'

MyExclude<string | number | (() => void), Function> // string | number

In plain english, we want our type to:

loop over everything in

`T`

, if it doesn't exist in`U`

include it in our new type

On paper, this sounds very similar to our approach for implementing our own Pick type, and a naive approach might look something like:

`type MyExclude<T extends (string | number | symbol), U> = {`

[Property in T]: Property extends U ? never : Property

}

Where we loop over everything in `T`

using a mapped type, and then use a conditional type to either exclude it (returning `never`

) or include it (returning `Property`

).

This solution partially works, but results in a type (for our first example case) of:

` MyExclude<'a' | 'b' | 'c', 'a'> // { a: never, b: 'b', c: 'c'}`

This is along the right lines, and could probably be coerced into the expected shape, but misses the point of this challenge.

To solve this we need to know one of the "super powers" of conditional types in TypeScript, that is they are distributive over unions. What does that mean?

This means when a conditional type is working on a union type, (`T extends something`

where T is a union type), then the condition is applied to each member of that union.

For example,

`type YesOrNo<T extends boolean> = T extends true ? "yes" : "no"`

When we call that type with one value:

`YesOrNo<true> // "yes"`

We get back the single type "yes", but when we call it with a union type:

`YesOrNo<true | false> // "yes" | "no"`

We get back a union type, where each element in the union has been applied to the type.

So the solution to our `MyExclude`

problem actually becomes very simple:

` type MyExclude<T, U> = T extends U ? never : T`

We use a conditional type `T extends U`

to check if `T`

exists in `U`

, if it does, we return `never`

, otherwise we include it in the resulting object. Returning `never`

works to exclude items, as `never`

gets dropped by union types that include it.

The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00014-easy-first/README.md

For example, given the following cases, our First type should return the type shown in the comments:

`First<[3, 2, 1]> // 3`

First<[() => 123, { a: string }]> // () => 123

First<[]> // never

First<[undefined]> // undefined

Like in the Tuple To Object, we're interested in the type of a specific element of an array. We can use indexed access types to do this.

We know we can access the type of the first element in an array with `T[0]`

so our initial implementation can be as simple as:

` type First<T extends any[]> = T[0]`

This works for 3 out of 4 of our example cases above, but fails for the empty case `First<[]>`

. We can see that:

`First<[]>`

is currently returning `undefined`

but the challenge requires it to return `never`

.

We can special case the empty array and use conditional types to solve this challenge. We want to say

if the array is empty, return never, otherwise return the type of the first element in our array

The syntax for conditional types looks like:

` type First<T extends any[]> = T extends [] ? never : T[0]`

Where `T extends []`

can be read as, if `T`

is empty.

The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00018-easy-tuple-length/README.md

For example, given the following cases, our Length type should return the type shown in the comments:

` Length<typeof tesla> // 4`

Length<typeof spaceX> // 5

Length<5> // @ts-expect-error

Length<'hello world'> // @ts-expect-error

Like in the Tuple To Object, we're interested in the type of a specific element of an array. We can use indexed access types to do this.

We know that in TypeScript, like JavaScript arrays are objects, and those objects have a `length`

property signifying their length. We therefore know that the `T["length"]`

should give us the length of an array.

` type Length<T> = T["length"]`

The above works, but throws TypeScript errors, as TypeScript doesn't have a guarantee that the type `T`

passed into length will be an array, it may therefore not have a `length`

property.

To solve this we can constrain the type of T to be only arrays:

` type Length<T extends any[]> = T["length"]`

This solves most of our issues but leaves us with two errors in our example cases above. The errors occur as when we call `Length<typeof tesla>`

the `typeof tesla`

is a readonly array. We can't assign a readonly array to a `any[]`

type, we therefore need to further constrain `T`

to only allow readonly arrays.

` type Length<T extends readonly any[]> = T["length"]`

This `readonly`

constraint makes sense, as if we pass in a mutable array to `Length`

, the only type that we will be able to get back will be `number`

, rather than the length of our array. This is because mutable arrays can be changed at runtime, so TypeScript cannot infer the length of it.

The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00011-easy-tuple-to-object/README.md

For example, given the following interface, our TupleToObject should generate this type.

`const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const`

type result = TupleToObject<typeof tuple> // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

Like in the Pick challenge, we need to create a new type based off an existing type, so therefore we can use a mapped types to do so.

Since we want our object type to contain key value pairs that both correspond to one entry in our readonly tuple, we could implement it like so:

`type TupleToObject<T extends readonly any[]> = {`

[Property in T]: Property

}

If this worked, it would create a new object type, with each key being `Property`

and each value being `Property`

, making our test cases pass.

Unfortunately this doesn't work as mapped types can only be used against union types, not readonly tuple types.

So we need to convert our `readonly[]`

type into a union type, and then loop over this union type.

We know that given for any `readonly[]`

we could construct it's union type by taking the type of the first element, the second, the third all the way up to the nth, like:

`const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const`

const TupleType = typeof tuple

type union = TupleType[0] | TupleType[1] | TupleType[2] // etc

This works as we can use index types to access the types of each element in the `readonly[]`

.

This works, but we need to know the length of our tuple upfront, instead we can use the `TupleType[number]`

syntax to generate a union of all of the types in a `readonly[]`

tuple.

Using `T[number]`

to convert our readonly array into a union type, and mapping over that union looks like:

`type TupleToObject<T extends readonly any[]> = {`

[Property in T[number]]: Property

}

Finally, we need to constrain the type of readonly arrays that we accept. Since at the moment you can pass:

`const t = TupleToObject<[[1, 2], {}]>`

without the TypeScript compiler complaining, but clearly our `TupleToObject`

type can't work on this type since `[1, 2]`

and `{}`

aren't valid keys in a typescript type.

We need to restrict our `any[]`

type to be only tuples that contain elements that are valid keys. Valid keys in typescript can be `string`

, `number`

or `symbol`

so our final type becomes:

`type TupleToObject<T extends readonly (string | number | symbol)[]> = {`

[Property in T[number]]: Property

}

]]>
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00268-easy-if/README.md

Coming soon

For example, given the following cases, our MyExclude type should return the type shown in the comments:

` If<true, 'a', 'b'> // 'a'`

If<false, 'a', 2> // 2

In plain english, we want our type to:

if C is true, return T, if C is false, return F

This is the textbook use-case for conditional types in TypeScript

We'll start by implementing a conditional type that returns T or F based on the value of C:

` type If<C, T, F> = C extends true ? T : F`

If C is assignable to true, return F, otherwise return F.

This is almost the complete solution, but at the moment our `C`

generic can take on any value, we want to constrain it to only accept boolean values. The final solution is:

` type If<C extends boolean, T, F> = C extends true ? T : F`

]]>
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00189-easy-awaited/README.md

For example, given the following cases, our Awaited type should return the type as shown in the promise:

` MyAwaited<Promise<string> // string`

MyAwaited<Promise<{ field: number }> // { field: number }

MyAwaited<Promise<Promise<string | number>> // string | number

MyAwaited<Promise<Promise<Promise<string | boolean>>> // string | boolean

The first two examples show a simple promise type being passed to `MyAwaited`

with the type inside that Promise being returned. The third and fourth examples show that our type needs to work with nested promises.

Lets consider only the first example case above:

` MyAwaited<Promise<string> // string`

We could write a type to resolve this to a string like so:

`type MyAwaited<T> = T extends Promise<string> ? string : never;`

In english this reads:

if you pass a promise of a string, return a string, otherwise return never

This only works for the first example case, but we could extend it to work for the second case. In english we could say:

if you pass a promise of a string, return a string, otherwise, if you pass a promise of an object type, return that object type, otherwise return never

We can extend our type to handle multiple cases:

`type MyAwaited<T> = T extends Promise<string>`

? string

: T extends Promise<{ field: number }>

? { field: number }

: never;

This would now work for the first two example cases, and could be extended indefinitely to handle all cases. But if we took this approach to handle all cases, our type would become infinitely long. Instead we need a generic solution to this problem.

When working with conditional types in TypeScript, we can make use of inference within conditional types.

Instead of extending our type, we can replace it with a generic version making use of the `infer`

keyword:

`type MyAwaited<T> = T extends Promise<infer InnerType> ? InnerType : never;`

This works for the first two example cases, in the first example InnerType takes on the type `string`

and returns that, in the second example it takes on the type `{field: number}`

and we return that.

This still doesn't solve the nested cases. At present, when we pass `Promise<Promise<string | number>>`

to our type, we currently get back `Promise<string | number>`

, i.e. it unwraps one level of Promises. We need to unwrap all the promises!

We can extend our type to work recursively:

`type MyAwaited<T> = T extends Promise<infer InnerType>`

? InnerType extends Promise<any>

? MyAwaited<InnerType>

: InnerType

: never;

Here we check if InnerType is still a promise (after being unwrapped once as per before), if it is, we call `MyAwaited`

on it again (the recursive call). If `InnerType`

is no longer a promise, we return it's type.

Finally, we need to constrain the type `T`

so that we can only pass Promise types to our type, and our final type looks like:

`type MyAwaited<T extends Promise<any>> = T extends Promise<infer InnerType>`

? InnerType extends Promise<any>

? MyAwaited<InnerType>

: InnerType

: never;

]]>
`Includes<T extends unknown[], U>`

that returns true if `U`

is included in `T`

.
The challenge: https://github.com/type-challenges/type-challenges/blob/main/questions/00898-easy-includes/README.md

The easier examples to solve this problem for are shown below:

For the given examples, our Includes type should return the type as shown in comment

` Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Kars'> // true`

Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'> // false

Includes<[1, 2, 3, 5, 6, 7], 7> // true

Includes<[1, 2, 3, 5, 6, 7], 4> // false

Includes<[1, 2, 3], 2> // true

Includes<[1, 2, 3], 1> // true

Includes<[false, 2, 3, 5, 6, 7], false> // true

Includes<[null], undefined> // false

Includes<[undefined], null> // false

These examples are all fairly simple, they include an array of types as `T`

and one specific type as `U`

. If U is inside `T`

we return true, otherwise we return false.

` Includes<[{}], { a: 'A' }> // false`

Includes<[boolean, 2, 3, 5, 6, 7], false> // false

Includes<[true, 2, 3, 5, 6, 7], boolean> // false

Includes<[{ a: 'A' }], { readonly a: 'A' }> // false

Includes<[{ readonly a: 'A' }], { a: 'A' }> // false

Includes<[1], 1 | 2> // false

Includes<[1 | 2], 1> // false

In these more complicated cases, the array `T`

includes complex types such as objects and type classes. For example in the second complex case, `false`

is assignable to `boolean`

but not equal to it, so `false`

is not inside `T`

despite `boolean`

being a member of `T`

.

Lets forget the complex use example cases for now. If you've been following the challenges, you may have taken the excludes challenge already. This challenge seems very similar although this time we want to return true if `U`

is in `T`

, not the other way round.

We know that working with tuple types when doing type manipulation can be simplified by turning a tuple into a union type like so:

`T[number]`

And once we've turned our tuple type into a union type we can simply ask if `U`

is assignable to it and write a simple type like so:

`type Includes<T extends readonly unknown[], U> = U extends T[number] ? true : false`

This converts our type `T`

to a union of all the members of the tuple, then checks to see if `U`

is assignable to to it. In this case, assignable to means "is equal to". If `U`

is, return true, else return false.

This works for the simple cases, but not the more advanced cases. Lets dig into these to find out why

For this example,

` Includes<[boolean, 2, 3, 5, 6, 7], false>`

Our type is currently returning true, but it should be returning false. Clearly `false`

isn't in our array, but the Includes type thinks it is. What's going on here?

The problem is with our equality check, we're asking our union type if `false`

is assignable to it. Well it is! `false`

is assignable to `boolean`

, as is `true`

. Clearly we need a better way of comparing types.

The type challenges come with a set of utility types that are used to make assertions in the playground. One of these types is called Equal. We won't go into how this type works in this post, but know that you can use it to compare the equality of two types:

` Equal<true, boolean> // returns false`

Equal<false, boolean> // also returns false

Now all we have to do is make use of this type in our `Includes`

type

To solve this challenge we need to abandon our naive solution and rethink the approach completely. Instead of converting our array into a union type, we're instead going to loop over the elements, and compare the equality of each one to `U`

using our `Equal`

type.

Unfortunately there's no looping construct when doing type manipulation, instead we'll have to rely on recursion. Our approach will be:

- Grab the first element from the array call it
`First`

- Grab everything else out of the array and call that
`Rest`

- Compare
`First`

to`U`

using`Equal`

- If they're equal, return true
- If not, call our
`Includes`

type again with`Rest`

and the existing`U`

- If we reach the end of the array, return false as we haven't found our element

In my opinion, the hardest part of the steps above is working out how we can grab the first element, and the rest of the elements out of the `T`

array.

To do this, we can use the `infer`

keyword. We can use this in a condition type like so:

` T extends [infer First, ...infer Rest] ? true : false`

`infer First`

is bound to the first element in the array, `...infer Rest`

is bound to everything else in the array, or the empty array if there are no other elements. This works very similarly to how it would in JavaScript.

TypeScript will only match `infer First`

if there is at least one element in the array, i.e. there is a type for typescript to infer. This means that the condition will return false when we pass the empty array. If there is only one element in the array `...infer Rest`

will bind to `[]`

, much like the spread operator in JavaScript.

Turning the steps into code leaves us with:

` type Includes<T extends readonly unknown[], U> = T extends [infer First, ...infer Rest]`

? Equal<First, U> extends true

? true

: Includes<Rest, U>

: false

We need the additional conditional type to compare the equality of `First`

and `U`

to true.

The recursive nature of this means the `T`

will become one element smaller each time we call it, eventually becoming `[]`

(if we don't find `U`

and `First`

). If `T`

does become `[]`

this is our base case of our recursive type, and we return `false`

as we fail the initial conditional check.

Coming soon...

It's possible to solve the FizzBuzz interview question using TypeScripts type system alone, without any run time code. I'm going to show you how.

The rules of FizzBuzz are simple:

For each number between 1 and a given number, print:

- "Fizz" if the number is divisible by 3
- "Buzz" if the number is divisible by 5
- "FizzBuzz" if the number is divisible by 3 and 5
- Otherwise print the number

In normal sane typescript this would be easy enough, something like:

`function fizzbuzz(n: number): void {`

for (let i = 1; i <= n; i++) {

if (i % 15 === 0) {

console.log("FizzBuzz");

} else if (i % 3 === 0) {

console.log("Fizz");

} else if (i % 5 === 0) {

console.log("Buzz");

} else {

console.log(i);

}

}

}

But this isn't all that interesting, instead I want a Type that can do this. I want this wall of types:

`type FizzBuzzRange<`

A extends number,

B extends number,

Tuple extends unknown[] = []

> = A extends B

? Tuple

: FizzBuzzRange<Add<A, 1>, B, [...Tuple, FizzBuzz<A>]>

type FizzBuzz<N extends number> = And<IsDivisibleBy3<N>, IfDivisibleBy5<N>>

? "FizzBuzz"

: IsDivisibleBy3<N> extends true

? "Fizz"

: IfDivisibleBy5<N> extends true

? "Buzz"

: N

Lets build this piece by piece.

You are going to need to know about:

- Generics
- Conditional types

So this syntax should make sense:

`type HelloOrGoodbye<T extends boolean> = `

T extends true

? "Hello"

: "Goodbye"

Basically we take a generic type T that's a boolean, if T extends true, which we'll equate to equals true, we return "Hello" otherwise we return false.

- Inference within conditional types

`type Flatten<T> = T extends Array<infer Item> ? Item : T;`

Here we're saying if our generic type T is an array, we want to get back the type of whats inside the array, otherwise give back T itself. The infer keyword is going to be really helpful to us when building types.

- Variadic tuple types

Sounds complicated, but isn't really. This can be thought of as similar to the spread operator working on arrays in JavaScript. Think:

`type Concat<A extends any[], B extends any[]> = [...A, ...B]`

Here we're combining two tuples together by "spreading" both.

- A whole bunch of recursion

Since we don't have loops in the type system. we're going to be using a lot of recursion

Lets break the FizzBuzz problem down to it's core, it's basically can you use the modulo operator? If we could build a Modulo operator in typescript, we'd be able to solve the problem

So assuming we can't use %, how would we build mod?

Well one way that makes sense to me, and a way that's going to work well for our use case is:

`function isDivisibleBy(a, b) {`

let counter = b;

while (a >= counter) {

if (counter === a) {

return 0;

}

counter += b;

}

return a - (counter - b);

}

A worked example would make sense:

For mod(9, 3)

We start a counter off at 3, then we loop until that counter is bigger than 10, adding three to the counter each time round the loop. Inside the loop we check if our counter === a, if it does we return 0. The first time through the loop a = 9, counter = 3, so this isn't met, the second time through a = 9, counter = 6, the third time however, a = 9, counter = 9, so we'll return the 0, indicating a 0 remainder

For the example mod(10, 3) We'll keep adding 3 to the counter until it reaches 12, at this point 12 is bigger than 10 so we exit the loop. We then need to work out the remainder. We take 3 off 12 to get back to the iteration before, then we do 10 - 9 to work out the remainder.

We know we don't have loops in the type system, but we do have recursion! So before we try and turn that into a type, lets build it with recursion:

`function modulo(a, b, counter = b) {`

if (counter === a) {

return 0

}

if (a < counter) {

return a - (counter - b);;

}

return modulo(a, b, (counter += b));

}

This is the exact same algorithm. Ok great. No lets turn that into a Type!

`type Modulo<A extends number, B extends number, Counter extends number = B> = `

A extends Counter

? 0

: A < Counter extends true

? A - (Counter - B)

: Modulo<A, B, Counter + B>

Here we're using extends to mean equals, that's not quite true but it's good enough for us.

I haven't lost the plot, this type isn't going to work. There are 3 problems with it.

Add, LessThan and Minus. We can't use normal operators in our types. We need to find some way of creating types that work like the operators do.

Lets start with Add, as it's the base of the rest.

Lets assume we want to build a type that when given two numbers returns the result of adding them:

`type Add<A extends number, B extends number> = ??`

Add<1, 2> // 3

Add<9, 3> // 12

Is the goal, we need to come up with a plan.

Adding is like combining two numbers, we can't add two numbers but we can combine two things, tuples!

Imagine we had this code in TS:

`function combine_arrays(a : unknown[], b: unknown[]) : unknown[] {`

return [...a, ...b]

}

A function that takes two arrays and returns a new array with all the elements from both.

Now if we asked for the length of that new array... it would be the length of array a + array b.

So this is how we could tackle Add. We can combine two tuples into one using variadic tuple types just like we can in JavaScript. If we had a Type that could turn a number into a tuple of that length, and a Type that could return the length of a tuple, we could have a way of building Add.

Lets work on the easy part first, a type that can return the Length of a tuple;

`type Length<A extends unknown[]> = A extends { length: infer L} ? L : never`

We use a conditional type to infer the length of the tuple and return that.

Now we need a way of building a tuple of a given length. We'll start with a number and aim to build a tuple that includes all of the numbers up to that number, for example:

`type Range<5> = [0, 1, 2, 3, 4]`

type Range<7> = [0, 1, 2, 3, 4, 5, 6]

We've called it Range as that's pretty much what it's doing. How would we build that?

`type Range<N extends number> = ???`

Lets take the same approach, build a recursive solution in JS and then turn it into a type:

`function range(n, tuple=[]) {`

if (tuple.length === n) {

return tuple;

}

return range(n, [...tuple, tuple.length])

}

So we're going to keep growing the tuple by adding a number representing the current length of it and eventually we'll return the tuple when it's the length expected.

In TypeScript that looks like a fairly simple recursive type:

`type Range<N extends number, Tuple extends number[] = []> = Length<Tuple> extends N`

? Tuple

: Range<N, [...Tuple, Length<Tuple>]>;

So now, building Add is fairly simple, we create a type called Add that takes two numbers,

`type Add<A extends number, B extends number> = ???`

Then we turn those numbers into tuples with their respective lengths, and we combine them together into one tuple:

`type Add<A extends number, B extends number> = [...Range<A>, ...Range<B>];`

And finally we return the length using out Length type:

`type Add<A extends number, B extends number> = Length<[...Range<A>, ...Range<B>]>;`

Ok so looking back at our modulo type, we can now fix it up a little:

`type Modulo<A extends number, B extends number, Accumulator extends number = B> = `

A extends Accumulator

? 0

: A < Accumulator extends true

? A - (Accumulator - B)

: Modulo<A, B, Accumulator + B>

The + can be replaced by our new Add type:

`type Modulo<A extends number, B extends number, Accumulator extends number = B> = `

A extends Accumulator

? 0

: A < Accumulator extends true

? A - (Accumulator - B)

: Modulo<A, B, Add<Accumulator + B>>

Our Modulo type looks better now, but we still have two problems, the < sign and the subtraction. Lets focus on the < less than since this is going to be pretty easy to build.

Ideally we'd like a type that we can use like so:

`LessThan<A, B>; // boolean`

It should take two numbers and return a boolean if A is less than B. But how should we build less than?

Your first instinct might be subtract a from b, and see if that is less than zero. But if we do that we're not closer to being able to build our type in the type system.

Instead, lets think about what we have built so far with our Range type.

If we turn B into the Range**, if A exists inside that tuple then it must be less than B, Example time:**

// LessThan<2, 5> // Range<5> = [0, 1, 2 ,3, 4] // 2 extends Range<5> // true

A case where it isn't less than:

// LessThan<5, 5> // Range<5> = [0, 1, 2, 3, 4] // 5 extends Range<5> // false as 5 is not less than 5

Ok, we should be able to build that!

`type LessThan<A extends number, B extends number> =`

A extends Range<B> ? true : false

But this isn't quite right, for example:

// LessThan<1, 2>

The condition is saying is 1 assignable to [1, 2], but that doesn't quite work, instead we need to turn the tuple into a union type to ask if a number is inside it.

// 1 is assignable to 1 | 2

We can do that with the `[number]`

syntax, so `Range<A>[number]`

would create a union `0 | 1 | 2 | 3`

We have to write this in two steps to stop TypeScript getting confused:

`type LessThan<`

A extends number,

B extends number,

BRange extends number[] = Range<B>

> = A extends BRange[number] ? true : false

Ok so now back to Modulo, lets replace our < with our new LessThan type:

`type Modulo<A extends number, B extends number, Counter extends number = B> = `

A extends Counter

? 0

: LessThan<A, Counter> extends true

? A - (Counter - B)

: Modulo<A, B, Add<Counter + B>>

So now there's just one issue left, subtract. Now here me out, we don't actually need subtract to get FizzBuzz working. We don't need to know the modulo to get FizzBuzz working, we only need to know if A is divisible by B or not. We don't need the remainder.

If we change our expectations to only get back true or false from this type, we're actually there. If we change the name to IsDivisible, and change our returns, we're there:

`type IsDivisible<A extends number, B extends number, Accumulator extends number = B> = `

A extends Accumulator

? true

: LessThan<A, Accumulator> extends true

? false

: IsDivisible<A, B, Add<Accumulator + B>>

Lets try it out:

We can now build two new types for IsDivisibleBy3 and IsDivisibleBy5:

`type IsDivisibleBy3<A extends number> = IsDivisible<A, 3>`

type IsDivisibleBy5<A extends number> = IsDivisible<A, 5>

An aside, this is kinda like partial application, if that's your thing.

We can now go back to the initial problem, FizzBuzz. We had this type:

`type FizzBuzz<N extends number> = IsDivisibleBy3<N> extends true ???`

And we now have that type!

Lets return Fizz if its divisible by 3, otherwise return the number passed in:

`type FizzBuzz<N extends number> = IsDivisibleBy3<N> extends true`

? "Fizz"

: N

Now we can add the IfDivisibleBy5 in as a nested conditional type:

`type FizzBuzz<N extends number> = IsDivisibleBy3<N> extends true`

? "Fizz"

: IfDivisibleBy5<N> extends true

? "Buzz"

: N

Now, the final piece of the puzzle. How do we do &&

`IsDivisibleB y3<N> && IfDivisibleBy5<N>`

Well, we build a type of course:

We can build a type called And that takes two generics, and returns true if both of them evaluate to true, and false otherwise:

`type And<A extends boolean, B extends boolean> = A extends true`

? B extends true

? true

: false

: false

So if A and B are true, we return true, if A is true but B is false we return false, and if A is false, we return false

We can use that type like:

`type FizzBuzz<N extends number> = And<IsDivisibleBy3<N>, IfDivisibleBy5<N>>`

? "FizzBuzz"

: IsDivisibleBy3<N> extends true

? "Fizz"

: IfDivisibleBy5<N> extends true

? "Buzz"

: N

And that should be a working type, it takes a number and returns either FizzBuzz, Fizz, Buzz or the number passed in.

Now, the final final puzzle piece, we want to build a type that can generate a tuple of FizzBuzzes over a range. For example:

`FizzBuzzRange<1, 10>`

Should generate the tuple:

// [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz"]

This should be quite simple using everything we have learnt so far:

We know we're going to use recursion to build up the tuple, so we know we'll take a third param in our type that eventually will get returned:

`type FizzBuzzRange<`

A extends number,

B extends number,

Tuple extends unknown[] = []

> = ???

Now if we add one to A each time through our "loop" and return when A is equal to B, we'd have the base case of our recursion:

`type FizzBuzzRange<`

A extends number,

B extends number,

Tuple extends unknown[] = []

> = A extends B

? Tuple

: ???

If A doesn't equal B, then we need to recursivly call our type again, adding the result of calling FizzBuzz to our tuple, and also incrementing A by one:

`type FizzBuzzRange<`

A extends number,

B extends number,

Tuple extends unknown[] = []

> = A extends B

? Tuple

: FizzBuzzRange<Add<A, 1>, B, [...Tuple, FizzBuzz<A>]>

And that's it, FizzBuzz built completely in the type system, zero run time typescript. Beautiful, but please never do this.

]]>