Type | Treat 2020 + решения
Памятуя, насколько интересными были задачки на Type | Treat 2021
, решил пройти Type | Treat 2020
.
Чтож, в 2020 году задачки были слабее. А главная претензия: далеко не всегда понятно из описания, что надо получить в результате. В 2021 уже стало значительно лучше. И со сложностью и с понятностью заданий.
Лента с анонсами и обсуждениями на dev.io
Day 1 Challenges
Beginner/Learner Challenge
Достаточно просто: выковырять тип из объекта
const displayHauntings = (haunting: GhostAPIResponse['hauntings'][number]) => {
Intermediate/Advanced Challenge
Подсказали, что нужно использовать conditional types. В сегодняшнем TS готовые хелперы лежат в Utility types (Exclude/Extract).
Вот решение без них
type helper<T,V> = T extends V ? T : never;
type AllCandies = helper<ResultsFromHalloween, { candy: true }>;
type AllTricks = helper<ResultsFromHalloween, { trick: true }>;
type inverse<T, V> = T extends V ? never : T;
type AllCandiesWithoutPeanuts = inverse<AllCandies, { peanuts: true }>;
А вот с ними:
type AllCandies = Extract<ResultsFromHalloween, { candy: true }>;
type AllTricks = Extract<ResultsFromHalloween, { trick: true }>;
type AllCandiesWithoutPeanuts = Exclude<AllCandies, { peanuts: true }>;
Day 2 Challenges
Beginner/Learner Challenge
Что-то перемудрил, можно же было просто typeof pumpkin
:
type Pumpkin = { [keys in keyof typeof pumpkin]: typeof pumpkin[keys] }
type PumpkinFromFunction = ReturnType<typeof createExamplePumpkin>
Intermediate/Advanced Challenge
Прикольно. Код трогать нельзя, можно только внизу дописать что-то.
Вот так получилось:
type God = { god: true };
function areGods(ghosts: Array<Ghosts | God>): ghosts is God[] {
return !!ghosts.length && ghosts.reduce((res, v) => res && !!(v as God).god, true);
}
type Demon = Extract<Ghosts, { demon: true }>;
function areDemons(ghosts: Ghosts[]): ghosts is Demon[] {
return !!ghosts.length && ghosts.reduce((res, v) => res && !!(v as Demon).demon, true);
}
type Ectoplasmic = Parameters<typeof shockAndTrap>[0][number];
function areEctoPlasmic(ghosts: Array<Ghosts | Ectoplasmic>): ghosts is Ectoplasmic[] {
return !!ghosts.length && ghosts.reduce((res, v) => res && !!(v as Ectoplasmic).ectoplasmic, true);
}
Day 3 Challenges
Beginner/Learner Challenge
Ужасно написанное задание. Я вообще не то сделал, что они ожидали. И посмотрел на решения других людей: похоже, что ВСЕ сделали не то.
Intermediate/Advanced Challenge
А тут как-то всё слишком просто
type TrunkOrTreatResults = {
[key in typeof trunkOrTreatSpots[number]]: {
done: boolean,
who: string,
loot: Record<string, any>
}
}
Day 4 Challenges
Beginner/Learner Challenge
Просто добавить константности…
type Room = Readonly<{
name: string
doors: number
windows: number
ghost?: any
}>
Intermediate/Advanced Challenge
Не знаю, как это сделать на 4.1, сделал на текущем TS
const winners = {} as { [keys in Lowercase<`${typeof breeds[number]}-${typeof costumes[number]}`> ]: ReturnType<typeof decideWinner> }
...
const id = `${breed}-${costume}`.toLowerCase() as Lowercase<`${typeof breed}-${typeof costume}`>
Посмотрел авторское решение: оказывается в 4.1 этот интринсик назывался “lowercase”. С маленькой буквы и без стрелочек
Day 5 Challenges
Beginner/Learner Challenge
Тут добавил дженерик с указанием изменяющихся параметров:
type House<N, T> = {
doorNumber: N;
trickOrTreat(): T;
restock(items: T): void;
}
Применять его так:
type FirstHouse = House<1, "book" | "candy">;
type SecondHouse = House<2, "toothbrush" | "mints">;
...
Intermediate/Advanced Challenge
Тоже шаблонные литералы, и тоже интринсик. Сделал на современном:
type CapitalName = `${Capitalize<keyof typeof moviesToShow>}`;
function makeScheduler(movies: typeof moviesToShow) {
const schedule = {} as Record<`${'getVHSFor' | 'makePopcornFor' | 'play'}${CapitalName}`, () => void>
for (const movie in Object.keys(movies)) {
const capitalName = movie.charAt(0).toUpperCase() + movie.slice(1) as CapitalName ;