TypeScript Exercises Bonus🦠 - Answers Part 1
Tags: typescript, javascript
Published: 2020-03-23 12:17:26

--- series: Advanced TypeScript Exercises ---
For details of questions and requirements please visit [the questions](
https://dev.to/macsikora/typescript-exercises-bonus-type-of-pandemia-1fd0). This post will include only answers. If you are not aware of what this is about, then please take some time with the questions article. Also I would recommend the read about [TypeScript type system as a language](https://dev.to/macsikora/typescript-is-more-than-you-think-2nbf), which can help with understanding what we are doing here.

This post will include half of the answers as questions and the solution difficulty is significantly higher than previous questions in the series.

### Answer 1
The question was: Make type level function which will check if two patients can meet. `CanMeet` should return or true or false depends if patients can or can't meet.

In order to achieve that we should use conditional type expression. This expression can be also nested in similar matter we use standard ternary operator.

```ts
type CanMeet<A extends Patient, B extends Patient> = 
  A extends Quarantine ? false // cannot meet with anybody
  : A extends Sick ? B extends Sick ? true : false // two sick people can meet
  : A extends Healthy ? B extends Healthy ? true : false // two healthy can meet
  : false // other combination cannot meet
```

Full solution in [the playground](https://www.typescriptlang.org/play?#code/C4TwDgpgBAyglgYwNZQLxQN4GdgENgQBcUA5FokiQL4BQokUAEhLgDbAAWIamO+RpDi3ZdqdcNACKAV1wAnXADtgcRdHTY8BYiQCOshctyqIY8QwAK+OBGU8MNKFEW4AtgJxzVAcxpUoAGRQABTwyFAAPkzCnNxRMvJKKmoAlADcNObQAFIA9hyK9i7uOnkF1IGwFFlQACq5rkVuAiT1rhVBzGyxNQDS-E0lpP0EHVXINQCycEjqmMUt07NjCYbJEDVW0qyDLVusY10iIDUAIrlyuaC7OueXoCsGSSY1AOJyEN4X3BoLOu+fb5jMJITY2OQIOYYP6kCzgyGPRLKF40AD0qKgMggODguUKVkUABMIK44LgoABGKAAWigrlwsyg9GgrAgADcIDsAGbSRQIFR4qAAdw4iA4wrgrB2CCE4TgXKZQtyUDA1lswCwUAQSjpEAgwEyzKgAGElJM9cAADwAQSgEAAHgQiZqrCp1QAaKAAITtjtshJdauUAD4eI4oLaHU6A5insi1FAAPxQLlsLAbJzESN+53jFDJn1R-2akFJplyaTQYip1jp8NZ33RzVHWJlws5mMtrhl4AVqsptMZqDVweGiRQMqKADqcE4bR4psU5v1lsnnraofRA9r0Fwmrx0DgmvI4SUhKgSiuQigR+cVxqk5nnBGc0Xy6ta6gL83GN7lYvmoAEZXheHxQCeoJGncVwgE+HAAl8cg-CaZoWpa0GgJ6CHfD+27pgBKoQLkYCsjehT6EieAmFqSiKFcur6heiggMBhInEaSwQHB87oG+aGceuDS4TW+F7oRxGkaoUAUWsxgJtqih0cADHKUoLG5Gxmy4Ns3ENAuqErvsgmuLhf7QCA2JQMBnCgdAQjdCcNBAA)

### Answer 2
The question was: Make type level function which will get all sick patients from the collection of patients. `GetSick` should filter the collection for only sick patients.

> **Note** below solution is made in TS 4.0 with use of [Variadic Tuple Types](https://github.com/microsoft/TypeScript/pull/39094). It was rewritten as previous solution had problems with new versions of TS.

```ts
// utility types needed for adding/removing head of list
type Unshift<A, T extends unknown[]> = [A, ...T];
type Shift<T extends Array<any>> = T extends [unknown, ...infer Rest] ? Rest : T

// below direct solution 
// we have compiler error about circular dependency 🛑:
type GetSickNotWorking<
Patients extends Patient[]
, SickPatients extends Patient[] = []
> 
= Patients['length'] extends 0 
? SickPatients 
: 
(Patients[0] extends Sick 
? GetSickNotWorking<Shift<Patients>, Unshift<Patients[0], SickPatients>> 
: GetSickNotWorking<Shift<Patients>, SickPatients>);

// working solution with a mapped hack:
type GetSick<
Patients extends Patient[]
, SickPatients extends Patient[] = []
> 
= Patients['length'] extends 0 
? SickPatients 
: {
  [K in keyof Patients]: 
  Patients[0] extends Sick 
  ? GetSick<Shift<Patients>, Unshift<Patients[0], SickPatients>> 
  : GetSick<Shift<Patients>, SickPatients>
  }[0];

``` 
The goal was filtering only sick patients from given collection of patients. This was achieved by utility types `Shift` and `Unshift` which allow on removing/adding elements from tuple types (tuple type is exactly our collection type at the type level).

**Explanation**

- Second argument `SickPatients` 🤒 is kind of accumulator, remember reduce function? The reason of having it is exactly accumulating sick patients.
- `K in keyof Patients` - its really hack in order to avoid circular dependency error
- `Patients['length'] extends 0 ? SickPatients` - if our Patients list is already empty we end the computation
- `Patients[0] extends Sick ? GetSick<Shift<Patients>, Unshift<Patients[0], SickPatients>> : GetSick<Shift<Patients>, SickPatients>` - if patient is sick we put it into SickPatients list by Unshift and remove it from Patients list. If Patient is not sick we remove it from Patients but without attaching it into SickPatients
- `[0]` we get first element, this is part of the hack

Let's follow the algorithm for the example use case (its simplified view):
```ts
// patients:
type John = {name: 'John'} & Sick
type Tom = {name: 'Tom'} & Healty
type Kate = {name: 'Kate'} & Sick

type Check = GetSick<[John,Tom,Kate]>
```
First iteration ➰:

- Patients: `[John,Tom, Kate]`
- SickPatients: `[]`
- We check if `John` is sick, he is
- We remove `John` from `Patients`
- We add `John` to the beginning of `SickPatients` // by Unshift
- We call next iteration

Second iteration ➰:

- Patients: `[Tom, Kate]`
- SickPatients: `[John]`
- We check if `Tom` is sick, he is not
- We remove `Tom` from `Patients`
- We call next iteration

Third iteration ➰:
- Patients: `[Kate]`
- SickPatients: `[John]`
- We check if `Kate` is sick, she is
- We remove `Kate` from `Patients`
- We add `Kate` to the `SickPatients`

Fourth iteration ➰:
- `Patients` list is empty
- calculation returns `SickPatients`

The result is `[Kate, John]`. As you can see order is reversed as we are adding items in the beginning. But the goal is achieved, we get the sick patients 👌

The full solution is available in [the playground](https://www.typescriptlang.org/play?ts=4.0.0-beta&ssl=27&ssc=26&pln=27&pc=1#code/C4TwDgpgBAyglgYwNZQLxQN4GdgENgQBcUA5FokiQL4BQokUAEhLgDbAAWIamO+RpDi3ZdqdcNACKAV1wAnXADtgcRdHTY8BYiQCOshctyqIY8QwAK+OBGU8MNKFEW4AtgJxzVAcxpUoAGRQABTwyFAAPkzCnNxRMvJKKmoAlADcNObQAFIA9hyK9i7uOnkF1IGwFFlQACq5rkVuAiT1rhVBzGyxNQDS-E0lpP0EHVXINQCycEjqmMUt07NjCYbJEDVW0qyDLVusY10iIDUAIrlyuaC7OueXoCsGSSY1AOJyEN4X3BoLOu+fb5jMJITY2OQIOYYP6kCzgyGPRLKF40AD0qKgMggODguUKVkUABMIK44LgoAAmKAAWigk1wsyg9GgrAgADcIDsAGbSRQIFR4qAAdw4iA4wrgrB23ggwCgbB25HCYGstmAWCgXMujU40AQuSlEH5uMKuS5UBVKjVWAAdJlmVAAKqKLCirnAAA8AEEADR1KAQAAeBCJGt5SEUuSFigA2gBdAB8PBjvqgNvTtTjGQdMDdntqAeDtkJGq9cgUIA9ShACaT6ALQZDJagMfDkejfvTNtUXIgcigACVscA41AAPyD4dQYi1e0SKCvWUgj00KxW5QaxvFjVrmzKeM0P0g3fWwtNneq-ej9AHutQE8bmMkVmKbycEijrehqAABnH4yQB91WnTBHBbXooFUKBZhAM170vdU42IICsBjH9PyLb8QX-RdgGXXM4HdD0UITP1nVdQjPRQtC4yPCgSKTYhcPwvNiIQrBSIAki-BojIagAYSEZAAEYeGYigPRjMCykUH0wLaOSnBGCA5MTKB0SgQSjSQUTXVybZCSgAAjaAYxkv1lLjAShKQKl0HE5BJLAgEvjkEBFPveEVLA5SPP2Gg1I0rSRKgPSDOM0zfIXD5XJAKyHWCpAAGYxKXCSpKcBSwP8wKMUS3SOH01hDJMls4yAA)

### Additional challenge 🔥
There was additional/extended question to the second one - Can you make state of the patient as an argument? And make function which will get patients for given condition? Example usage would be `Get<Patients, Healthy>`. As we have now `GetSick` implemented, can you try to make it more flexible? Put your answer in the comment section (preferred playground link).

### Try yourself with the rest of questions! 🔥
There are two questions more in [The Bonus Questions](https://dev.to/macsikora/typescript-exercises-bonus-type-of-pandemia-1fd0). As you see the solution of the first two questions, maybe it will inspire you to make other two. Don't give up, check your skills 💪.

**This series will continue**. If you want to know about new exciting questions from advanced TypeScript please follow me on [dev.to](https://dev.to/macsikora) and [twitter](https://twitter.com/macsikora). **Be healthy and take care!**