---
theme: gaia
_class: lead
paginate: true
backgroundColor: #00437a
color: #fff
---

# **Typescript**

![bg left:40% 80% drop-shadow:0,0,0,#fff](img/IServ_Logo_White.png)

Endlich ruhig schlafen bei der Frontend-Entwicklung. 😴

---

# Was ist Typescript?

Zusatzinformationen über Typen für Javascript.

---

# Fehlt es Javascript an Types?

```js
var data; // Was darf hier rein?
```

---

# Fehlt es Javascript an Types?
```js
> var data = "some string";
> console.log(data);
"some string"
> data = 15; // Why not both?
> console.log(data);
15

```
---

# Jetzt mit Types!

---

# Jetzt mit Types!

```ts
var data: string = "some string";
console.log(data);
data = 15; // ❌ Error
console.log(data);
```

---

## Transparenz von Schnittstellen

Was tut diese Library?
```js
// @iserv/graph.js
export function drawGraph(data, options = {}) {
    [... Implementierungsdetails]
}
```

---

## Transparenz von Schnittstellen

Was tut diese Library?
```js
// @iserv/graph.js
export function drawGraph(data, options = {}) {
    [... Implementierungsdetails]
}
```

Besser: Wie benutze ich diese Library?

---

## Transparenz von Schnittstellen

```js
// @iserv/graph.js
export function drawGraph(data, options = {}) {
    [... Implementierungsdetails]
}

// your-module.js
drawGraph([{
    x: 2,
    y: 5,
}, {
    x: 3,
    y: 7,
}]);
```

---

## Transparenz von Schnittstellen

```js
// @iserv/graph.js
export function drawGraph(data, options = {}) {
    [... Implementierungsdetails]
}

// your-module.js
drawGraph([
    5,
    7
]);
```

---

## Transparenz von Schnittstellen

```js
// @iserv/graph.js
export function drawGraph(data, options = {}) {
    [... Implementierungsdetails]
}

// your-module.js
drawGraph([
    5,
    7
], {
    start: 0,
    stepSize: 1,
});
```

---

## Dafür hat man doch JSDoc!

```js
// @iserv/graph.js
/**
 * @typedef {Object} GraphOptions
 * @property {HTMLCanvasElement} mount
 * @property {number} start
 * @property {number} stepSize
 * 
 * @param {GraphOptions} options
 */
export function drawGraph(data, options = {}) {
    [...Implementierungsdetail]
}
// your-module.js
drawGraph(
    data, 
    {
        mount: document.getElementById('my-canvas'),
        start: 2,
        stepSize: 1,
    },
)
```

---

## Warum nicht JSDoc?

![bg left:50% 100%](img/self-documenting.png)
* JSDoc kann lügen
* Wird nicht automatisch überprüft

---

## Typescript aufsetzen

![bg left:50% 210%](img/busy-doggo.png)

* In neuem Projekt
* Integration mit Webpack

---

## Typescript in einem neuen Projekt

Installieren

```
npm install -g typescript         # global
npm install --save-dev typescript # lokal
```

---

## Typescript in einem neuen Projekt

Neues Projekt

```
tsc --init
```

* (Lokal ist der Befehl dann `npx tsc [...]`)

---

## Konfiguration

tsconfig.json
```json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}
```

---

## Kompilieren

```
tsc [<file>]
```

---

## Kompilieren
```ts
// index.ts
let variable: number = 5;

variable = 10;
```
<one `tsc` later>
```js
// index.js
"use strict";
let variable = 5;
variable = 10;
```
---
## Integration in Webpack-Projekten


---
## Integration in Webpack-Projekten

![bg 90%](img/webpack-typescript-bundling.png)

---

## Integration in Webpack-Projekten
```
npm install --save-dev typescript ts-loader
                                  ^^^^^^^^^
```

---
## Integration in Webpack-Projekten
```js
// webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js'],
    },
    // [...]
};
```
---

## Integration in bestehende Projekte

![bg left:50% 100%](img/typescript-integration.png)

---

## Typescript in Javascript?

* TS in JS integrieren geht ohne Probleme
* ```ts
  // extension.ts
  export function getFileExtension(path: string): string {
      return path.split(".").slice(-1);
  }
  // path.js
  import {getFileExtension} from './extension.ts';
  console.log(getFileExtension("some/image.png"));
  // > "png"
  ```
---

## Javascript in Typescript?
* JS in TS integrieren ist schwierig
* ```ts
  // extension.js
  export function getFileExtension(path) {
      return path.split(".").slice(-1);
  }
  // path.ts
  import {getFileExtension} from './extension.ts';
  console.log(getFileExtension("some/image.png"));
  ```

---
## Javascript in Typescript
```
path.ts:1:32 - error TS7016: Could not find a declaration file
 for module './extension.js'.
'./extension.js' implicitly has an 'any' type.

1 import {getFileExtension} from './extension.js';
                                 ~~~~~~~~~~~~~~~~
Found 1 error in path.ts:1
```

---

![bg 60%](img/typescript-migration-1.png)

---

![bg 60%](img/typescript-migration-2.png)

---

![bg 60%](img/typescript-migration-3.png)

---

## Javascript in Typescript

Wie damit umgehen?
* Typescript auf weniger strikt stellen
  * => Nutzung von Typescript verliert an Wert
* Alle Abhängigkeiten direkt nach Typescript konvertieren
  * Nicht immer machbar
* Schnittstellen mit Typen versehen

---

![bg 60%](img/typescript-migration-4.png)

---

## Schnittstellen typisieren

```ts
// extension.d.ts
export function getFileExtension(path: string): string;
```

---

## Schnittstellen typisieren

* Keine Implementierung
* Kein Type-Checking der Implementierung
* Schnittstellen werden wenigstens typisiert `¯\_(ツ)_/¯`
* Das geht auch mit JS-Libraries

---

## Wie beschreibe ich nun meine Daten?

```js
const workerBee = {
    role: 'worker',
    name: 'Larry',
    age: 15,
};
```

---

## Objekte

```ts
const workerBee: Bee = {
    role: 'worker',
    name: 'Larry',
    age: 15,
};
```

```ts
type Bee = {
    role: string,
    name: string,
    age: number,
};
```

---

## Semantische Typen

```ts
const workerBee: Bee = {
    role: 'worker',
    name: 'Larry',
    age: 15,
};
```

```ts
type Bee = {
    role: BeeRole,
    name: string,
    age: Months,
};
type BeeRole = 'worker'|'queen'|'guard';
type Months = number;
```

---

![bg 60%](img/bee-type.png)

---

## Dictionaries

```js
const userNames = {
    '652a4707-3043-4ca9-b417-24feac0f5953': 'Bernhard',
    '017daef7-e1f1-4160-81ff-e5b17e86fc6b': 'Frieda',
};
```

---

## Dictionaries

```ts
const userNames: UserNameDictionary = {
    '652a4707-3043-4ca9-b417-24feac0f5953': 'Bernhard',
    '017daef7-e1f1-4160-81ff-e5b17e86fc6b': 'Frieda',
};
type UserId = string;
type UserNameDictionary = Record<UserId, string>;
```
---

## Dictionaries (alternative)

```ts
const userNames: UserNameDictionary = {
    '652a4707-3043-4ca9-b417-24feac0f5953': 'Bernhard',
    '017daef7-e1f1-4160-81ff-e5b17e86fc6b': 'Frieda',
};
type UserId = string;
type UserNameDictionary = {
    [UserId]: string;
};
```

---

## Optionale Properties

```js
const lkw = {
    anzahlRaeder: 18,
    hubraum: 25,
};
const bobbycar = {
    anzahlRaeder: 4,
};
```

---

## Optionale Properties

```ts
const lkw: Car = {
    anzahlRaeder: 18,
    hubraum: 25,
};
const bobbycar: Car = {
    anzahlRaeder: 4,
};
type Kubikmeter = number;
type Car = {
  anzahlRaeder: number,
  hubraum?: Kubikmeter,
};
```

---

## Nur optionale Properties

```ts
type Vehicle = Partial<{
  anzahlRaeder: number,
  hubraum: Kubikmeter,
  anzahlKufen: number,
}>;
```
![bg right:60% 100%](img/bobbycar.png)
![bg right:60% 130%](img/hovercraft.png)
![bg right:60% 170%](img/hubschraubär.png)

---

## Nur optionale Properties

```ts
type Vehicle = Partial<{
  anzahlRaeder: number,
  hubraum: Kubikmeter,
  anzahlKufen: number,
}>;
const helikopter: Vehicle = {
    anzahlKufen: 2,
};
```

---

## Nur optionale Properties

```ts
type Vehicle = Partial<{
  anzahlRaeder: number,
  hubraum: Kubikmeter,
  anzahlKufen: number,
}>;
const helikopter: Vehicle = {
    anzahlKufen: 2,
};
const bobbyCar: Vehicle = {
    anzahlRaeder: 4,
};
```

---

## Nur optionale Properties

```ts
type Vehicle = Partial<{
  anzahlRaeder: number,
  hubraum: Kubikmeter,
  anzahlKufen: number,
}>;
const helikopter: Vehicle = {
    anzahlKufen: 2,
};
const bobbyCar: Vehicle = {
    anzahlRaeder: 4,
};
const luftKissenFahrzeug: Vehicle = {
    hubraum: 10,
};
```

---

## Readonly

```ts
// @iserv/colors.ts
export type Color = string;
export type Colors = Record<'RED'|'GREEN'|'BLUE', Color>
export const colors: Colors = {
    RED: '#ff0000',
    GREEN: '#00ff00',
    BLUE: '#0000ff',
};
```

---

## Readonly

```ts
// @iserv/colors.ts
export type Color = string;
export type Colors = Record<'RED'|'GREEN'|'BLUE', Color>
export const colors: Colors = {
    RED: '#ff0000',
    GREEN: '#00ff00',
    BLUE: '#0000ff',
};
```
```ts
// consumer.ts
import {colors} from '@iserv/colors.ts';
colors = {}; // verboten wegen const
```

---

## Readonly

```ts
// @iserv/colors.ts
export type Color = string;
export type Colors = Record<'RED'|'GREEN'|'BLUE', Color>
export const colors: Colors = {
    RED: '#ff0000',
    GREEN: '#00ff00',
    BLUE: '#0000ff',
};
```
```ts
// consumer.ts
import {colors} from '@iserv/colors.ts';
colors = {}; // verboten wegen const
colors.BLUE = colors.RED; // erlaubt 😢
```

---

## Readonly

```ts
// @iserv/colors.ts
export type Color = string;
export type Colors = Record<'RED'|'GREEN'|'BLUE', Color>
export const colors: Readonly<Colors> = {
    RED: '#ff0000',  ^^^^^^^^
    GREEN: '#00ff00',
    BLUE: '#0000ff',
};
```
```ts
// consumer.ts
import {colors} from '@iserv/colors.ts';
colors = {}; // verboten wegen const
colors.BLUE = colors.RED; // verbiet 😎
```

---