Type | Treat 2021 - Wrap-up
Tags: typescript, challenge
Published: 2021-10-30 14:31:39

---
title: Type | Treat 2021 - Wrap-up
published: true
description: The TypeScript Team challenges
tags: typescript,challenge
cover_image: https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2021/10/type-or-treat-2021.png
series: type | treat 2021
---
## Type | Treat Challenge Wrap-up

That's all the challenges done! If you missed any of the challenges they're all available in [the Playground here](https://www.typescriptlang.org/play?#gist/927ccc66ae3022dc64c4f650109b937a). Let's talk through the final answers to day 5's challenges.

## Yesterday's Solution
### Beginner/Learner Challenge

In this challenge we were working with an existing object literal which had been `as const`d. The goal was to use `keyof` and `typeof` to extract interesting sets of strings from the object. The first being the keys in the object:

```diff
- type SchemeNames = "background" | "textColor" | "highlightOne"
+ type SchemaNames = keyof typeof scheme
```

Idealy you might have noticed the 'key of' in the comment, which could have led you to `keyof`, from there you needed to re-use `typeof` to extract the type from `scheme`. This gets all of the keys from that constant.

Next, we asked if you could improve

```ts
function possibleSchemeItems(colors: any): string[] {
    const keys = Object.keys(colors) as string[]
    return keys
}
```

In this case, you can switch `string` to `SchemeNames` - this example was made so that there was an interesting function to play around with. You could switch `colors` to `typeof schema` but nothing you do around `Object.keys` would keep the types retained. This is kind of interesting, the reasoning is that TypeScript cannot make _reasonable_ guarantees that the return value of `Object.keys` actually _is_ `keyof typeof colors` (because of JavaScript prototype chaining) and so you have to re-type that line. Interesting.

```ts
function possibleSchemeItems(colors: typeof scheme): SchemaNames[] {
    const keys = Object.keys(colors) as SchemaNames[]
    return keys
}
```

Next we had you figure out how to get the values of `schema` as a union:

```diff
- type PossibleColors = '#242424' | '#ffa52d' | '#cafe37'
+ type PossibleColors = typeof scheme[SchemaNames]
```

We tried to be quite explicit in the clue leading up to this one, because jumping to an indexed type might not be instinctive for beginners. This we considered to be the trickiest part of the challenge.

Then to wrap up the challenge, and to make sure the types you are creating are constructive in a real world-ish scenario, we presented a `Record` to see if you knew that the first parameter can be a list of keys:

```diff
- type Scheme = Record<string, string>;
+ type Scheme = Record<SchemaNames, string>;
```

Which would cause a compiler error with `previousScheme` - letting you know it worked.

[Our answer](https://www.typescriptlang.org/play?#code/PTAEDEHsCdQFwBYFNQAkCGAbTkDuSkA7UfJAayIBMAaUAT0gFcByANxUqQGMBLTy+JFBcE6QgHMUiJACgQoAM5I4oSADNhkHNAWg1Mek1gNGsfACMFPOFKHmUCgA6RIZOvGQBbJJRlywAOoIPJgoJszQKMiRtCagnuju6Lr42KDoXCqYPBTpoOIuAgpcTHD+6YQCPJ6O0JDsHiglnObJKLjBoYYskaDRSABcfiWECirFXigAvKAA3jKgi6CtXGTidYyVA6DMAMQATAAsR0fM1AtLNgAecADCWjDbe2pq6ACs+5RnF4vB4gjZf5wADyhEGO12XHQaiQAGYAOzfJZ9Hj-QEIOAAFVwkCeuwAnEh9gAGF7MGQAX3SuhGYz88gAklkXGRdNlciZYHA6I52sERKBIrUkEpCHBdFhMKBnAorOYuuUStpdDxdKVVBpKOgbLQocQ4iIxJIPKr4DzbKByvZhJFtT5QJQeJFMph3Go6p5GqAKHQ1RoAAYTJDef3pcz1JAAfj83N5oAAyiJg+gAHLoby6GY+9Rm3k5oPeelgJmgHCuNk5KT9Zi6RCmxhKNSMKVNwiZHiQYj+mVy0KJyZM4MKf3lDo8AU45sCSJwUzEaSgQjpkUar1Koy6cyMFTWQXKOcS8pjaA8CQS6DQRIAOlAtzE3VA1VqEZNCmjMlb7c70sgsp48qQftgyQQdPAUAAKdcdG2MQ6AASm2ICEjTDMAG0AF05h+TRRhUH1M1AYFzAAK24OAr3wyCHh0ODqQTJNkOXBQMOwmc529JBfUpItQAATSYRRnDgGwBDESBpFgKElFXe9Si1ETFDgE8JFATYO0IXUxHKA1QnvOtdEYRxBGWdwyzIU9xHSFQF1jFB8wY9AKl8eRpGIU9OCuCzVGs5Afz-ADFAcxcmPfFzzVAAAFX9eyQe5lVAGY9hOY5DmYUAAB8IRed5PjSzK9ihGEEXJWzIui-9QjimACNs+zJlQ7MNFqjQCyQdC-HKFM8A8bVujYJpdLBARDMaaTbIUWIBNwMRrKEBIKCPUwq16iSkBrPISkcdwcwXGBUVPLBAsmRSQildANkqK9yjvfUBPmhwlp6nyUG7SJWA7BskKQUN7BwXATrSUQFHKBcFGXDjfTohdAwY77VKM9Bw3Yd9Sq+hLQAAJW4GBKAAHiQ1MmNoY8LIAPgAbmGTsxmlN6PoUL7ENh9H5mRFY1guyg8QARl5vmkUuJAbiq6A8S4AA2YkAA5iWJAXflRAFFZBME8Vl8XWm574KXJoA)

### Intermediate/Advanced Challenge 

For this challenge, we started with the type we wanted you to write, and then tried to find incremental steps which built up in complexity till you hit it.

The total change we were looking for was this:

```ts
function handleSale(events: Record<string, (e: Books) => void>) {
  // ... 
}
```

To:

```ts
function handleSale(events: { [Book in Books as `on${Book["genre"]}`]?: (e: Book) => void }) {
  // ... 
}
```

Getting there is a bit of a jump!

We first asked you to switch the `string` in the `Record` to be `Books`:

```diff
- function handleSale(events: Record<string, (e: Books) => void>) {
+ function handleSale(events: Record<keyof IncomingBookMap, (e: Books) => void>) {
```

The next step was to remove the `Record` and replace it with its underlaying mapped type:

```diff
- function handleSale(events: Record<string, (e: Books) => void>) {
+ function handleSale(events: { [Book in keyof IncomingBookMap]?: (e: Books) => void }) {
```

The `?` being the key that if you searched the TypeScript documentation for ["mapping modifier"](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers) you'd see the documentation around [mapped types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers) which we also improved in the process of making this challenge.

We thought that could be enough for some folk, and that was a good pausing point and thus classed the final change as a bonus. That jump revolved around using key remapping via `as` in the mapped type. 

```
- function handleSale(events: { [Book in keyof IncomingBookMap]?: (e: Books) => void }) {
+ function handleSale(events: { [Book in Books as `on${Book["genre"]}`]?: (e: Book) => void }) {
```

The `IncomingBookMap` existed specifically to add the prefix `on` to the genre of each book, which is handled by template string literals. All of the documentation for these concepts are in the same page, so after a few reads it should hopefully all make sense.

This system is _more or less_ how the DOM's event system works, and is what the idea is loosely based on, [from `lib.dom.d.ts`](https://github.com/microsoft/TypeScript-DOM-lib-generator/blob/008041c9638d034fc2cb366994c9bd79a43fac36/baselines/dom.generated.d.ts#L4549-L4563):

```ts
interface DocumentAndElementEventHandlersEventMap {
    "copy": ClipboardEvent;
    "cut": ClipboardEvent;
    "paste": ClipboardEvent;
}

interface DocumentAndElementEventHandlers {
        addEventListener<K extends keyof DocumentAndElementEventHandlersEventMap>(type: K, listener: (this: DocumentAndElementEventHandlers, ev: DocumentAndElementEventHandlersEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
}
```

Roughly translates to english as "DocumentAndElementEventHandlersEventMap" shows how to handle `document.addEventListener("copy", (evt) => { ... })` and what to map the first argument of that function to. The DOM types can't really switch to use a template literal because not all properties have an `on` prefix, but it's a pretty logical expansion of the idea in specific cases.

[Our answer](https://www.typescriptlang.org/play?#code/PTAEE0HsFcHICcCmp7QHZoJZoOagIagBGkkA1gM4AWkADgDQFoAmoz082eAEvgDZ9IAd0SI0oAJ4wAUCFBV8AN2SEKtRAGNM-UADNI8eQfgHipSsXwVErSOJpDQAW3xoJoHDQoAXCrLDeVIhIBCHYoIHIJOQAdNLS2N7BuvgayABC5qAA3h5iSABcoD6cuIz4tLR8EgAimBQaMGjeRQAUzPWN6C2gaNBORMEAlKAAvAB8oIqQmKygAL4A3PFyAGKmFJhOVZha3hKMIrACBBQU-ciRIfghdtURQpB5aEgUjETQ3v6gs4j890dWHxMGRLk98MxWFZnK53NDaJAzpgiHxkHx8ElDMxhOJIqBgWhEHEEs1kqlkNxjAZMuRQIgAB5JFgUUA0sg5Z6FUAAIho8BM8G5jE8iO8AGEmj0+gNgoxFLtvFsKBLukVpYNDPMSZiUmlQAAlSAuNBpNl0xliZgss25HD5RBFbkmY1pIWgWgmbz4HB2ereABy+CcDuK3lKeC10n26lZ5hZo1AlP51KyAB8DUbXKbzMtvlBoKAhK5vBEngoWKiIkFivxkNBNrgmHTlM0ALQUCQ+RBOQ5UXZUfFx-Eg5CwOwAbTtL0QAF0xpNWtEyENYHE5AAVJ4uUGSGCGYG6ZB-Tay3cFhTKAgw2igSC6KtHlu+UsPzCGJcs7xPSJv5tiEtoEGDorAEEgxgAkiaRpcGyACyFRjDk3ygLeaB8gKRRJgKbLLHIKF2M6WYhoaLqIDh3yRnI+aGIgT7FJ2SROIO5AssCO6BPU7yfIWQTiFIBY+DcJZfgQGhpGcD4EJCmCKnYOi6JgiB8Fa3x2HSqQDlOITrmBiAAMoaJwtAloJ8DPiJOCYJewQChQMSgOuCjeLALJoJAJY4EgGIFPE5bMKiem1q02TSPhaFUvAi7mCMIUoShS4xBUVS1J0kpRbEIo+F0zSgAAVKAACsQyhQs9DSPMIwgYmwSIC5km6OgGiyeIQhBCE-HHHwxDINiXCSY88BkIwGiuGeoCNGgyhmVW9R6I1zUvn5lbfLQVgNnggQmNAniSY0-KaMJukvnie1IE1c0ms19kAOq1SEPp9SJYZwiwhYGOyakyT8JpIMGzT-AcxSQN82JoLAJaHkpw47vxvSiKwIkAFb9DeImEOo8CHudrgUCIhgSIg3jEg1l2YGpS36UFtH-hQRS5OOZrhGyLLQgABnYAAk2RsuO3JaYg3IzvMrMzgA-G0IZsiMExTDMrAVUhKFyLdCDIJgOBueGklbFU3b-hiZPiMwhP4JgfAsvohgcRb82G3EStgLBfxYGUkl3O4CJIiiyADeysOEjYL7Yj8LLhHirPU80FCs+6NxBgQJDKHEkb+GAelJDeACMVViqNsPbsgrMU4FqIxyTTWG6h9ypGkxmgOz4XJvAMeuKwDeESaiAtyyoKdqL8QD6noDp4gN4AExVf6whVhi9d2O5bUx7Np0Hfc8Cm+tTY2QYjCwyN4i-ZAl4ycScgAPK4k5xTQEQiMHcNecwDCO5F63AW1i3YmjyWdjIHekleS6uXBagw+r4CINYZootQDrBovSIMutGCcE8ABYQ3xYYXjBN9DQfBoDGzni8TMncY4fBLF9bEiBXILy4PZTc7poAnGtreXQ94Or3RmI2ESAcEZPG+AXIGwZ3RIG8PsC6zAgL-S6hocsdpPzfmrNGP+94I5PmjqcM8nU4aB0IC4SofUnCQA6ApYIp8wDrkwLQIoNQ7Dg1APWQuAAFIS2g+Bl1MNbYkg8h4jxvAAZlAJPaegRZ54mAYbFmIRrAlmgAwH4zlPxbCwX2YS1YXDhA9JAb2Tgih4kUX4OQltJKsyXEvNAmx8F-GkRdCualuFyO6pYawthL7IEAoI-+eJI5EwCXIXOfEn6rQksEshaBLYuAWptGAO1cm6X7l4kCYBMh9FpsPDOoAAAsATvh9MLMgQ+l48TcL0KYVmkFGhOBguYeCtAW6MMgHaK4SClISD6hQSAqJ7hqVZszGOIlDJ-CSJJPJ-cqIwE0UckS9iBGXG7FUDEyASj6NcBYhhBs1IiSEOvG8MTJL-jfMgMJdhiRAA).

### Thanks!

There are a few people involved in getting `Types | Treat` running whose name you don't see on the masthead: [Gabriella](https://twitter.com/NoWaySheCodes) and [Daniel](https://twitter.com/drosenwasser) on the TypeScript team, and the folks in the TypeScript Community Discord - especially [webstrand](https://github.com/webstrand) and [michael](https://twitter.com/M_Rutter). My wife, [Danger](https://github.com/dangermcshane), should probably also get a shout for helping to provide themes - we've done 40 challenges so far and have to dig pretty deep occasionally to be fun and topical.

#### Feedback

If you gave `Types | Treat` a shot, we love for you to run through our [6 question survey](https://www.surveymonkey.com/r/FSQ7DLC) which help us figure out how to change and improve. Feedback on Twitter is useful, but there's only so much context you can gve in 280 characters!

### From here?

If you've not done [the 2020 `Type | Treat`](https://www.typescriptlang.org/play/#gist/303ebff59a6fc37f88c86e86dbdeb0e8-0), it's also good!

If you want to challenge yourself further, check out [types-challenges](https://github.com/type-challenges/type-challenges#intro) this clever system of type challenges goes all the way up to "very challenging for the TypeScript team" and also run entirely in the TypeScript Playgound. It's great work.