# 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