For details of the questions and requirements please visit the questions. This post will include only answers for last two questions. 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, which can help with understanding what we are doing here.
This post includes half of the answers, first part can be found - TypeScript Exercises Bonus🦠 - Answers Part 1
Answer 3
The question was: Make type level function which will check if given list of patients can be accommodated into the hospital with given list of free beds 🛌.
// remove first item from the tuple
type Shift<T extends Array<any>>
= ((...a: T) => any) extends ((a: any, ...result: infer Result) => any) ? Result : never;
// alternative version would be simpler with
// Variadic Tuple Types available from TS 4.0
type Shift<T extends Array<any>> = T extends [unknown, ...infer Rest] ? Rest : T;
type _Accomodate<
Beds extends '🛌'[],
Patients extends Patient[],
> = Beds['length'] extends 0 ? Patients['length'] extends 0 ? true : false :
Patients['length'] extends 0 ? true : { x: _Accomodate<Shift<Beds>, Shift<Patients>> }
type _TraverseA<T> = T extends object ? {
[K in keyof T]: T[K] extends boolean ? T[K] : _TraverseA<T[K]>
}[keyof T] : T
type CanAccomodate
< Beds extends '🛌'[]
, Patients extends Patient[]
, _A = _Accomodate<Beds, Patients>>
= _TraverseA<_A>
Ok, so now what we did here. We made three functions - _Accomodate
, _TraverseA
and the final CanAccomodate
.
Function _Accomodate
:
- takes list of beds and list of patients as arguments
- recursively calls itself until beds or patients list will be empty
- in every iteration its removes element from both lists by
Shift
-
{ x: _Accomodate<Shift<Beds>, Shift<Patients>> }
- we need to use container type in order to avoid TS blocking us with infinite recursive call, so its kinda hack 🏴☠️ - function creates structure with a shape
{x: x: x: true | false}
, where amount of levels is equal to smaller list size, the last value is saying ifPatients
list is longer (false), or is smaller or equal (true)
Function _TraverseA
:
- takes an object or boolean
- checks recursively if boolean it gives it back (this is the result)
- if not it recursively traverse the object until the boolean will be found
- finally it returns the final boolean in the structure prepared by
_Accomodate
Function CanAccomodate
- it is final composition of
_Accomodate
and_TraverseA
- it calls
_Traverse
on object type made by_Accomodate
Full solution in the playground
Answer 4
The question was: Make type level function which will group people from the given list. The three groups are people sick 🤒, people healthy 💪, people in quarantine 🔒.
// utility types needed
type Unshift<A, T extends Array<any>>
= ((a: A, ...b: T) => any) extends ((...result: infer Result) => any) ? Result : never;
type Shift<T extends Array<any>>
= ((...a: T) => any) extends ((a: any, ...result: infer Result) => any) ? Result : never;
type AddPatient<S extends Segregated, P extends Patient> = {
sick: P extends Sick ? Unshift<P, S['sick']> : S['sick'],
quarantine: P extends Quarantine ? Unshift<[P], S['quarantine']> : S['quarantine'],
healthy: P extends Healty ? Unshift<P, S['healthy']> : S['healthy'],
}
type Segragate
<Patients extends Patient[]
, Result extends Segregated = {sick: [], quarantine: [], healthy: []}
,_Next extends Patient[] = Shift<Patients>
,_NextSize extends number = _Next['length']
> = {
[K in (keyof Patients)]:
Patients[K] extends Patient ?
_NextSize extends 0
? AddPatient<Result, Patients[K]>
: Segragate<_Next, AddPatient<Result, Patients[K]>>
: never
}[0]
Function AddPatient
:
- makes wanted result structure with three sections for patients (sick, healthy,quarantine)
- for quarantine it additionally puts patient into isolation by
[P]
Function Segragate
:
- Make recursive call until list of patients is not empty
- For every iteration it calls
AddPatient
in order to put patient into correct section, and also removes this patient from the list as it was already used
Caution the function is not ideal 😪, for bigger list of patients it gives an error about infinite call. Maybe you can make it better? Give it a try 💪
The full solution is available in the playground
This series will continue. If you want to know about new exciting questions from advanced TypeScript please follow me on dev.to and twitter. Be healthy and take care!
Top comments (4)
Solution 4 works for 3.8, but for 3.9.2
AfterSegregation
becameundefined
Yes thanks. I believe I have fixed that already in last update.
I think I found much more simpler solution to question 3, just 2 lines:
Playground Link
4:
Playground Link