# TypeScript Cookbook This is a random collection (in no particular order) of "Recipes" and tips that I've collected over time, about how to be more effective using TypeScript. ## 📖 Create a type that is a derived map from another type: ```typescript= interface Foo { bar: string; blah: number; flip: 'flop' | null, yippie?: 123 | 456 | 789 } // This is a new type based on Foo, which has every property of Foo but now each property can be a boolean in addition to whatever it could have been before type FooBar = { [K in keyof Foo]: Foo[K] | boolean }; ``` ## 💡 It's often not safe to use ! (non-null assertion) in lambdas TypeScript will complain about the possibility of null if you use an object in a lambda. In some cases, TypeScript will be wrong, but in more cases than you think, it will be right. Consider this code snippet: ```typescript= let el = document.getElementById('stephen'); if (!el) { el = document.createElement('div'); window.requestAnimationFrame(() => { el!.removeAttribute('blah'); }); } goDoSomeWork(el); function goDoSomeWork(myEl: HTMLElement) { setTimeout(() => { el = null; }, 3) } ``` At first glance, this looks safe, and you wonder why TS insists that `el` could be `null`. After all, `el` is *definitely* created if it wasn't found, so what's the problem? It's that the function being invoked is a lambda to `requestAnimationFrame` which means it is NOT guaranteed to run immediately after line 3. Because of line 9 and that fact that your lambda is merely queued for exeution, this will, indeed, cause a runtime error. It's worth noting that TS will complain even for synchronous execution of lambdas. For example, if you tried to set the same style properties inside a `forEach`, TS will still complain, however, in that case it would be safe. Still, I recommend using `?` in both cases. In the first case it can actually prevent a runtime error, and in the second case, you never know when someone might change your code later, making the `!` unsafe. Here's a better option: ```typescript= let el = document.getElementById('stephen'); if (!el) { el = document.createElement('div'); window.requestAnimationFrame(() => { el?.removeAttribute('blah'); }); } goDoSomeWork(el); function goDoSomeWork(myEl: HTMLElement) { setTimeout(() => { el = null; }, 3) } ``` ## 💡 Be careful with optional properties and type guards In the following example, TypeScript complains about the last line of code: ``"Property 'canFly' does not exist on type 'never'"`` ```typescript interface Bird { canFly: true; } interface FlyingSnake extends Bird { isPoisonous?: boolean; } class Parrot implements FlyingSnake { canFly: true = true; } function isBird(parrot: Parrot): parrot is Bird { return !!'does not matter'; } const p = new Parrot(); if (isBird(p)) { throw new Error('It is a bird'); } console.log(p.canFly); ```typescript