## Typescript Essential Training
🔹 *parent* [[⧋ Typescript|Typescript]]
▫️ *related* [[⏶ Basic types|Basic types]], [[⏶ Union types|Union types]], [[Decorators and Dynamic Behavior (Typescript)|Decorators]], [[Module basics|Module basics]]
### Overview
From [LinkedIn Learning Course](https://www.linkedin.com/learning/typescript-essential-training-14687057/)[^1]
### Challenges
**Challenge 1: Basic Typescript Usage**
Challenge:
- Create an interface to create the structure of the variable `todoItems` (only items in array)
- Strongly type some hard-coded values with an `enum`
- Then, apply types to the parameters in order to return values of functions `addTodoItem()` and `getNextId()`
- Use a generic type to define the parameter of `getNextId()`
```ts
const todoItems = [
{ id: 1, title: "Learn HTML", status: "done", completedOn: new Date("2021-09-11") },
{ id: 2, title: "Learn TypeScript", status: "in-progress" },
{ id: 3, title: "Write the best app in the world", status: "todo" },
]
function addTodoItem(todo) {
const id = getNextId(todoItems)
const newTodo = {
id,
title: todo,
status: "todo",
}
todoItems.push(newTodo)
return newTodo
}
function getNextId(items) {
return items.reduce((max, x) => x.id > max ? max : x.id, 0) + 1
}
const newTodo = addTodoItem("Buy lots of stuff with all the money we make from the app")
console.log(JSON.stringify(newTodo))
```
Solution:
```ts
interface Todo {
id: number
title: string
status: TodoStatus
completedOn?: Date
}
enum TodoStatus {
Todo = "todo",
InProgress = "in-progress",
Done = "done"
}
const todoItems: Todo[] = [
{ id: 1, title: "Learn HTML", status: TodoStatus.Done, completedOn: new Date("2021-09-11") },
{ id: 2, title: "Learn TypeScript", status: TodoStatus.InProgress },
{ id: 3, title: "Write the best app in the world", status: TodoStatus.Todo },
]
function addTodoItem(todo: string): Todo {
const id = getNextId(todoItems)
const newTodo = {
id,
title: todo,
status: TodoStatus.Todo,
}
todoItems.push(newTodo)
return newTodo
}
function getNextId<T extends { id: number }>(items: T[]): number {
return items.reduce((max, x) => x.id > max ? max : x.id, 0) + 1
}
const newTodo = addTodoItem("Buy lots of stuff with all the money we make from the app")
console.log(JSON.stringify(newTodo))
```
#### Challenge 2: The Right Type
1. Replace line 3 type with the right type for this scenario
2. Object matches line 28-31, an object that matches the properties of the object in the array above it (24-26) - each property will be a function that accepts the value of that property and returns true if the value matches the function
3. If you hover over the name parameter on line 29 you will see 'string' instead of warning
```ts
function query<T>(
items: T[],
query: any // <--- replace this!
) {
return items.filter(item => {
// iterate through each of the item's properties
for (const property of Object.keys(item)) {
// get the query for this property name
const propertyQuery = query[property]
// see if this property value matches the query
if (propertyQuery && propertyQuery(item[property])) {
return true
}
}
// nothing matched so return false
return false
})
}
const matches = query(
[
{ name: "Ted", age: 12 },
{ name: "Angie", age: 31 }
],
{
name: name => name === "Angie",
age: age => age > 30
})
```
Solution -
- `[Tprop in keyof T]` is the map, with T being the property value.
- `?:` specifies that it's an optional return value
- `(val: T[Tprop])` returns a value by getting the key T to return the [TProp] value
```ts
{
[TProp in keyof T]?: (val: T[TProp]) => boolean
}
```
```ts
function query<T>(
items: T[],
query: {
[TProp in keyof T]?: (val: T[TProp]) => boolean
} // <--- replace this!
) {
return items.filter(item => {
// iterate through each of the item's properties
for (const property of Object.keys(item)) {
// get the query for this property name
const propertyQuery = query[property]
// see if this property value matches the query
if (propertyQuery && propertyQuery(item[property])) {
return true
}
}
// nothing matched so return false
return false
})
}
const matches = query(
[
{ name: "Ted", age: 12 },
{ name: "Angie", age: 31 }
],
{
name: name => name === "Angie",
age: age => age > 30
})
```
### References
[^1]: LinkedIn Learning (2022). *Typescript Essential Training*, [Course](https://www.linkedin.com/learning/typescript-essential-training-14687057/)