1 of 116

Workshop

TypeScript Introduction

workshops.de

2 of 116

Hint for trainers

  • Report each change or addition to the trainers’ Discord-Channel.
  • Tell which Slide is affected, why the change is important and what benefit your change provides.
  • Use the code-highlighting-app if you work with code-snippets.
  • Use the following slide if you want to repeat certain topics of the workshop.

workshops.de

3 of 116

Task: Test your knowledge

@ts-ignore

Interfaces

Type Alias

strictNullChecks

any

Enum

Utility types

Type inference

Generics

TypeScript

workshops.de

4 of 116

TypeScript

JavaScript with syntax for types

workshops.de

5 of 116

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.

workshops.de

6 of 116

TypeScript is a superset

  • Superset of ECMAScript
  • Compiles to clean code
  • Optional Types

ES5

ES20XX

TypeScript

workshops.de

7 of 116

Why TypeScript

workshops.de

8 of 116

Why TypeScript

  • Types make code more secure
  • Understand how to use a function by just looking at its declaration
  • Types serve as documentation (e.g. what comes in and what goes out of functions)
  • Statement completion and code refactoring
  • Familiarity with other typed programming languages
  • Be safe against JS type coercions
  • Avoid simple unit tests (expect(service.get).toBeDefined)

The result: better maintenance for long-living projects

workshops.de

9 of 116

Types

workshops.de

10 of 116

Types in TypeScript - Variables

Types exist for primitive types.

let isDone: boolean = true;�

let size: number = 42;�

let firstName: string = 'Lena';

<code>

workshops.de

11 of 116

Types in TypeScript - Variables

Types exist for reference types.

const attendees: string[] = ['Elias', 'Anna'];

const attendees: Array<string> = ['Elias', 'Anna'];

const attendees: ReadonlyArray<string> = ['Elias', 'Anna'];

const myPair: [string, number] = ['Elias', 22];

<code>

workshops.de

12 of 116

Types - any

any takes any type. You are in JavaScript-Land.

let question: any = 'Can be a string';�

question = 6 * 7;�question = false;

<code>

workshops.de

13 of 116

Types - unknown

unknown takes any type - but you cannot access any property unless you check for its existence

let vAny: any = 10; // We can assign anything to any

let vUnknown: unknown = 10; // We can assign anything to unknown just like any

let s1: string = vAny; // value of type any is assignable to anything

let s2: string = vUnknown; // Invalid: value of type unknown (vUnknown) can't be assigned to any other type (without an explicit assertion)

vAny.method(); // ok anything goes with any

vUnknown.method(); // not ok, we don't know anything about this variable

<code>

workshops.de

14 of 116

The type unknown is more defensive than any.

workshops.de

15 of 116

Type inference

workshops.de

16 of 116

Type inference

You don’t have to set the type of a variable if the compiler can infer it.

let firstName = 'Max'; // string

let age = 30; // number

let isEmployed = true; // boolean

let friends = ['Stefan', 'Frederike']; // string[]

let dayOfBirth = Date.parse('...'); // Date

<code>

workshops.de

17 of 116

null and undefined

workshops.de

18 of 116

By default each data type in TypeScript does not accept null and undefined.

workshops.de

19 of 116

Compiler Flag: strict

Strict is a shorthand activating multiple rules

strict

strictNullChecks

strictProperty-

Initialisation

strictFunction-�Types

strict-

BindCallApply

<code>

workshops.de

20 of 116

Compiler Flag: strict

// tsconfig.json

{

"compilerOptions": {

"strict": "true"

// ...

}

// ...

}

<code>

workshops.de

21 of 116

Compiler Flag: strict

In strict null checking mode, the null and undefined values are not in the domain of every type.

let firstName : string | null = null;

let age : number | undefined = undefined;

let isEmployed : boolean | undefined;

// TypeScript Errors

let firstName : string = null;

let age : number = undefined;

let isEmployed : boolean; // undefined

<code>

workshops.de

22 of 116

Functions

workshops.de

23 of 116

Functions - Types

Add types to function parameters and return values.

function sayHi(firstName: string): void {� console.log(firstName);�}

<code>

workshops.de

24 of 116

Functions - Optional parameters

Parameters can be optional. Use a question mark.

function buildName(firstName: string, lastName?: string) {� if (lastName) {� return firstName + ' ' + lastName;� } else {� return firstName;� }�}

<code>

workshops.de

25 of 116

Functions - Default parameters

Function arguments can have defaults for arguments.

// type Inference: lastName is a string

function buildName(firstName: string, lastName?: string = 'Bond') {� return firstName + ' ' + lastName;�}

<code>

workshops.de

26 of 116

Object property checks:

Interfaces & Type Aliases

workshops.de

27 of 116

There are two syntactical flavors to type objects and values:

Interface, Type-Alias

workshops.de

28 of 116

Interfaces and Type Aliases

interface Book {� isbn: string;

title: string;�}

type Book = {

isbn: string;

title: string;

}

Interface

Type Alias

Give the structure of an object a name

let book: Book;

book = {

isbn: '978-1593272821',

title: 'Eloquent JavaScript'

};

const book: Book = {

isbn: '978-1593272821',

title: 'Eloquent JavaScript'

};

<code>

workshops.de

29 of 116

Optional properties

interface Book {� isbn: string;

title: string;� pages?: number;�}

type Book = {

isbn: string;

title: string;

pages?: number;

}

Interface

Type Alias

Properties can be optional.

const book: Book = {

isbn: 'Goethe, Johann Wolfgang: Faust. Der Tragödie Erster Teil',

title: '978-3-15-000001-4',

}

<code>

workshops.de

30 of 116

Optional properties

interface Book {� isbn: string;

title: string;� pages?: number;�}

interface Book {

isbn: string;

title: string;

pages: number | undefined;

}

Optional property is not equivalent to property which may be undefined.

const book: Book = {

isbn: 'Goethe, Johann Wolfgang: Faust. Der Tragödie Erster Teil',

title: '978-3-15-000001-4',

}

// Property 'pages' is missing in type '{ isbn: string; title: string; }' but required in type 'Book'.

<code>

workshops.de

31 of 116

Nesting

interface Profile {

id: number;

gender: string;

name: string;

pictureUrl?: string;

address: {

street: string,

zipCode: string,

city: string,

}

}

Interface

Type Alias

Interfaces and Type Aliases can be nested

type Profile = {

id: number;

gender: string;

name: string;

pictureUrl?: string;

address: {

street: string;

zipCode: string;

city: string;

}

}

<code>

workshops.de

32 of 116

Extends & Intersection Type

interface Book {� isbn: string;

title: string;� pages?: number;�}

type Book = {

isbn: string;

title: string;

pages?: number;

}

Interface

Type Alias

interface Magazine extends Book {

coverUrl: string;

}

type Magazine = Book & {

coverUrl: string;

};

The properties of Book are merged into Magazine.

<code>

workshops.de

33 of 116

Union Type

type Style = {

position?: string;

padding?: string | number;

margin?: string | number;

// other style properties

}

Interface

Type Alias

interface Style {

position?: string;

padding?: string | number;

margin?: string | number;

// other style properties

}

const style: Style = {

padding: '15px'

}

Expect a property to be either one or the other

Alternative 1

Alternative 2

const style: Style = {

padding: 15

}

<code>

workshops.de

34 of 116

Union Type

interface Book {

title: string;� isbn: string;

}

interface Magazine {

title: string;

issn: string;

}

type ReadingMaterial = Book | Magazine;

const readingMaterial: ReadingMaterial[] = [

{

title: 'Vogue',

issn: '0042-8000',

},

{

title: 'Robinson Crusoe',

isbn: '978-3401002569'

}

]

Common Pattern: Discriminating Unions

<code>

workshops.de

35 of 116

Union Types

interface Book {� title: string;

isbn: string;

}

interface Magazine {

title: string;

issn: string;

}

type ReadingMaterial = Book | Magazine | { id: string } | A ;

const getBook = (title: string): ReadingMaterial | undefined =>

readingMaterial.find(rM => rM.title === title)

The properties of Book are merged into Magazine.

<code>

workshops.de

36 of 116

Interfaces

Give an interface a name and use it as a type for variables.

interface Book {� isbn: string;

title: string;�}��const book: Book;

book = {

isbn: '978-1593272821',

title: 'Eloquent JavaScript'

};

<code>

workshops.de

37 of 116

Type Aliases

Declare type alias by giving it a name & define its shape

type Book = {� isbn: string;

title: string;�}��const book: Book;

book = {

isbn: '978-1593272821',

title: 'Eloquent JavaScript'

};

<code>

workshops.de

38 of 116

When to use Interfaces

workshops.de

39 of 116

Interfaces

An Interface can be implemented by a class.

class Biography implements Book {

isbn: string;

title: string;

}

<code>

workshops.de

40 of 116

Interface Merging

interface Book {

isbn: string;

title: string;

}

// other code...

interface Book {

pages?: number;

}

When re-declaring interfaces, its properties merge

interface Book {

isbn: string;

title: string;

pages?: number;

}

<code>

workshops.de

41 of 116

Interfaces - Class types

Forgetting to implement flipPage throws a compile error.

interface CanFlip {� flipPage: Function;�}

class BookListComponent implements CanFlip {��}

Class 'BookListComponent' incorrectly implements interface 'CanFlip'.

Property 'flipPage' is missing in type 'BookListComponent' but required in type 'CanFlip'.

<code>

workshops.de

42 of 116

When to use Type Aliases

workshops.de

43 of 116

Type Alias for unions of type literals

You can allow certain valid values for a type

// Example 1

type HttpStatusCodes = 200 | 201 | 400;

// Example 2

type TextAlignOptions = 'left' | 'right' | 'center' | 'auto' | 'justify';

<code>

workshops.de

44 of 116

Type Alias for unions of interfaces

interface Book {

title: string;� isbn: string;

}

interface Magazine {

title: string;

issn: string;

}

type ReadingMaterial = Book | Magazine;

const readingMaterial: ReadingMaterial[] = [

{

title: 'Vogue',

issn: '0042-8000',

},

{

title: 'Robinson Crusoe',

isbn: '978-3401002569'

}

]

Common Pattern: Discriminating Unions

<code>

workshops.de

45 of 116

Type alias for primitive types

type ContractId = string;

type CustomerId = string;

export interface Contract {

id: ContractId;

customerId: CustomerId;

}

Use type aliases to provide more context (as a form of documentation)

<code>

workshops.de

46 of 116

Interfaces vs. Type Aliases

workshops.de

47 of 116

Interface vs. Type Alias

“Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable..”

TypeScript Docs

<code>

workshops.de

48 of 116

Function Types

workshops.de

49 of 116

Function Types as Type Alias

type OnSuccess = (result: string) => void;

function doSomething(onSuccess: OnSuccess) {

// Some async code calls the callback

}

const onSuccess: OnSuccess = (result: string) => console.log(result);

doSomething(onSuccess);

The type of a function can be given as type alias

<code>

workshops.de

50 of 116

Function Types as Interface

interface OnSuccess {

(result: string): void;

}

function doSomething(onSuccess: OnSuccess) {

// Some async code

}

const onSuccess: OnSuccess = (result: string) => console.log(result);

doSomething(onSuccess);

The type of a function can be given as an interface (it’s an object).

<code>

workshops.de

51 of 116

TypeScript Generics

workshops.de

52 of 116

TypeScript Generics

The Array-Type is implemented as a generic.

const books: Array<number>= []

const list: ReadonlyArray<string> = ["foo", "bar"];

const books: Array<{title: string, isbn: string}> = []

const books: Array<Book> = []

<code>

workshops.de

53 of 116

TypeScript Generics

Generic object

type Response<T> = {

id: number;

data: T[];

createdAt: number;

modifiedAt: number;

};

const response: Response<Book> = {

id: 1,

data: [{ isbn: 'abc', title: 'Faust' }],

createdAt: 12345678,

modifiedAt: 12345678,

}

<code>

workshops.de

54 of 116

Generic Functions

Input argument is of same type as return value

const logIdentity = <T>(arg: T): T => {

console.log(arg);

return arg;

};

<code>

workshops.de

55 of 116

Generic Functions

Reverse a list: what gets passed into the function should be of the same type of what gets returned

const reverse = <T>(items: T[]): T[] => {

let result = [];

for (let i = items.length - 1; i >= 0; i--) {

result.push(items[i]);

}

return result;

}

<code>

workshops.de

56 of 116

Generic Functions

Reverse a list: what gets passed into the function should be of the same type of what gets returned

const reversed = reverse([3, 2, 1]) // [1, 2, 3]

// Safety!

reversed[0] = '1'; // Error!

const reverse = <T>(items: T[]): T[] => {

let result = [];

for (let i = items.length - 1; i >= 0; i--) {

result.push(items[i]);

}

return result;

}

<code>

workshops.de

57 of 116

Generic Functions

Placement of the generic identifier in fat-arrow functions

function reverse<T>(items: T[]): T[] { /* ... */ }

// vs

const reverse = <T>(items: T[]): T[] => { /* ... */ }

<code>

workshops.de

58 of 116

Update the TypeScript

definitions

Task

workshops.de

59 of 116

Advanced Types

workshops.de

60 of 116

Enums

workshops.de

61 of 116

Enum

Using enums can make it easier to document intent, or create a set of distinct cases.

enum Progress {

min = 0,

max = 100,

}

<code>

workshops.de

62 of 116

Enum

Using enums can make it easier to document intent, or create a set of distinct cases.

enum LogLevel {

ERROR,

WARN,

INFO,

DEBUG

}

enum LogLevel {

ERROR = 0,

WARN = 1,

INFO = 2,

DEBUG = 3,

}

Is equivalent

<code>

workshops.de

63 of 116

Enum

Named enum

enum Gender {

Female = 'FEMALE',

Male = 'MALE',

Other = 'OTHER',

}

<code>

workshops.de

64 of 116

Records

workshops.de

65 of 116

Record

Define type of all key and value pairs of object

const months: Record<string, number> = {

january: 1,

february: 2,

march: 3,

april: 4,

mai: 5,

june: 6,

july: 7,

august: 8,

september: 9,

october: 10,

november: 11,

december: 12,

};

<code>

workshops.de

66 of 116

Record

Define type of all key and value pairs of object

const arrayToObject = (values: number[]): Record<string, number> => {

// ...

};

const getNumberFormatSettings = (): Record<string, string> => ({

decimalSeparator: '.',

groupingSeparator: ',',

});

<code>

workshops.de

67 of 116

Excess Property Checks

workshops.de

68 of 116

Excess Property Checks

Not defined properties cause a warning when directly giving a type to an object literal.

interface Car {

wheels: number;

engine: string;

}

const tesla: Car = {

wheels: 4,

engine: 'electric',

cameras: 20, // Error

}

<code>

workshops.de

69 of 116

Excess Property Checks

Not defined properties cause an error when directly giving a type to an object literal.

interface Car {

wheels: number;

engine: string;

}

const tesla = {

wheels: 4,

engine: 'electric',

cameras: 20,

}

const myTesla: Car = tesla;

No TypeScript Error

<code>

workshops.de

70 of 116

Indexable Types

Object with certain properties but arbitrary additional properties.

interface Car {

wheels: number;

engine: string;

[key: string]: unknown;

}

const myTesla: Car = {

wheels: 4,

engine: 'electric',

cameras: 20,

}

<code>

workshops.de

71 of 116

Utility types

workshops.de

72 of 116

Partial

Make all properties optional

type FormValues = {

firstName: string;

surname: string;

dateOfBirth: Date;

gender: Gender;

};

const initialValues: Partial<FormValues> = { ...storedUserData };

type FormValuesPartial = {

firstName?: string;

surname?: string;

dateOfBirth?: Date;

gender?: Gender;

};

<code>

workshops.de

73 of 116

Omit and Pick

omit certain properties of an object or pick only certain properties

interface Book {

id: number;

isbn: string;

title: string;

pages?: number;

}

type BookId = Pick<Book, 'id'>

type BookId = { id: Book['id'] };

type BookId = Omit<Book, 'isbn' | 'title' | 'pages'>;

const Id = {

id: 12,

}

Three solutions which all lead to the same type.

<code>

workshops.de

74 of 116

Omit and Pick

omit certain properties of an object or pick only certain properties

interface Book {

id: number;

isbn: string;

title: string;

pages?: number;

}

type BookDetails = Pick<Book, 'title' | 'pages'>;

type BookDetails = Omit<Book, 'id' | 'isbn'>;

type BookDetails = {

title: Book['title'];

pages?: Book['pages'];

}

const details: BookDetails = {

title: 'Hamlet',

pages: 67,

}

Three solutions which all lead to the same type.

<code>

workshops.de

75 of 116

Combining Utility types

Combine utility types with other types to create more powerful types.

interface Book {

id: string,

title: string,

isbn: string,

}

// Example 1

type OptionalBookPropsWithoutId = Omit<Partial<Book>, 'id'>;

// Example 2

type BookWithNumberId = Omit<Book, 'id'> & { id: number };

<code>

workshops.de

76 of 116

Utility types

Use utility types to remain rename refactoring safe

interface Titles {

bookTitles: Array<Pick<Book, 'title'>>

videoTitles: Array<Pick<Video, 'title'>>

}

<code>

workshops.de

77 of 116

Compose TypeScript’s utility types

workshops.de

78 of 116

Partial<T> makes all properties of a type optional. What if we want to make only a few properties optional?

We can create our own utility type Optional<>.

workshops.de

79 of 116

How to read a complex type definition

This is how you can use it to make a property optional.

interface Customer {

id: string;

firstName: string;

lastName: string;

}

const optionalCustomer: Optional<Customer, 'firstName' | 'lastName'> = {

id: "12",

}

<code>

workshops.de

80 of 116

How to read a complex type definition

Solution: This is how Optional can look like.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

Let’s break this type down into pieces and learn how we can read & understand complex custom types.

<code>

workshops.de

81 of 116

How to read a complex type definition

We create a new type and sharing it with other modules.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

82 of 116

How to read a complex type definition

We name the type “Optional”.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

83 of 116

How to read a complex type definition

“Optional” has two parameters:

  1. The Object that should be made partially optional.
  2. The properties of the object that should be optional.

K has to be a property name of the Object.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

84 of 116

How to read a complex type definition

Make the Object completely optional.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

85 of 116

How to read a complex type definition

Take only the optional properties being specified in K.

interface AandB { a: string, b: string };

Pick<Partial<AandB>, "b"> // Result: { b?: string }

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

86 of 116

How to read a complex type definition

Combine the result from Pick<...> with the result form Omit<...>.

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

87 of 116

How to read a complex type definition

Use the given object T but remove all properties specified by K.

interface AandB { a: string, b: string };

Omit<AandB, "b"> // { a: string }

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

88 of 116

How to read a complex type definition

Put both results together:

// { b?: string } // { a: string }

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

89 of 116

How to read a complex type definition

The specified Key has been made optional.

{

a: string,

b?: string

}

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

<code>

workshops.de

90 of 116

Type Guards

workshops.de

91 of 116

Type Guards | built-in

With the JavaScript typeof operator we can check for a type

interface MayBeExecutable {

work?: () => void; // possibly undefined

}

function executer(unit: MayBeExecutable) {

if (typeof unit.work === 'function') {

unit.work();

}

}

<code>

workshops.de

92 of 116

Type Guards | built-in

Check for class instance with instanceof

const a = new Greeting(); // has method hi

const b = new Farewell(); // has method bye

function do(interaction: Greeting | Farewell) {

if (interaction instanceof Greeting) {

interaction.hi(); // type Greeting is inferred

} else {

interaction.bye(); // type Farewell is inferred,

// since no other type is possible

}

}

<code>

workshops.de

93 of 116

Type Guards | Custom

Help the TypeScript compiler to understand your types better.

// Example 1

function isNumber(value: string | number): value is number {

return !isNaN(value);

}

// Example 2

function isGoldCustomer(customer: NormalCustomer | GoldCustomer)

: customer is GoldCustomer

{

return customer.type === 'Gold';

}

<code>

workshops.de

94 of 116

Type Assertion

(Type Cast)

workshops.de

95 of 116

Type Assertions (Type Casts)

Override the compiler’s type checker. It comes in two syntax forms:

// Casting object literal to Person type: `as` syntax

const person = {

name: 'Victoria',

age: 28,

} as Person

// Casting object literal to Person: `ang-bracket` syntax

const person = <Person>{

name: 'Franz',

age: 34,

};

<code>

workshops.de

96 of 116

Type Assertions (Type Casts)

Dangerous use of type assertion: Can you be certain that persons array is not empty?

type Person = { name: string, age?: number };

// const persons = [ ... array of persons retrieved from API ];

// TS Error: Type 'undefined' is not assignable to type 'Person'.

const getPerson = (name: string): Person =>

persons.find(person => person.name === name);

// Solution 1: Union with undefined

const getPerson = (name: string): Person | undefined =>

persons.find(person => person.name === name);

// Solution 2: Type assertion (Use with caution! Can cause bugs!)

const getPerson = (name: string): Person =>

persons.find(person => person.name === name) as Person;

<code>

workshops.de

97 of 116

Type Assertions (Type Casts)

Valid use of type assertion: Help the compiler to understand what it could not do itself, but which you as the developer know for sure.

const deserialize = <T>(data: string): T => JSON.parse(data) as T;

const victoria = deserialize<Person>(

'{"name":"Victoria", "age":28}'

);

<code>

workshops.de

98 of 116

keyof Operator

workshops.de

99 of 116

keyof Operator

Takes an object type and produces a literal union of its keys

type Point = { x: number; y: number };

type P = keyof Point;

// Same as: type P = 'x' | 'y';

const x: P = 'x';

const y: P = 'y';

const z: P = 'z'; // Error: Type '"z"' is not assignable to type 'keyof Point'.

<code>

workshops.de

100 of 116

keyof with Enums

Create type out of enum

enum LogLevel {

ERROR,

WARN,

INFO,

DEBUG

}

enum LogLevel {

ERROR = 0,

WARN = 1,

INFO = 2,

DEBUG = 3,

}

type LogLevelStrings = keyof typeof LogLevel;

// This is equivalent to:

// type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';

Equivalent enums

<code>

workshops.de

101 of 116

TypeScript & React

workshops.de

102 of 116

Generic functions

and TSX

workshops.de

103 of 116

Generic Functions

Recap: Reverse list example

const reverse = <T>(items: T[]): T[] => {

let result = [];

for (let i = items.length - 1; i >= 0; i--) {

result.push(items[i]);

}

return result;

}

<code>

workshops.de

104 of 116

Generic Functions & React

In .tsx files you have to differentiate between JSX syntax and TypeScript generics.

const reverse = <T,>(items: T[]): T[] => {

let result = [];

for (let i = items.length - 1; i >= 0; i--) {

result.push(items[i]);

}

return result;

}

<code>

workshops.de

105 of 116

Generic Functions & React

In .tsx files you have to differentiate between JSX syntax and TypeScript generics - Alternative.

const reverse = <T extends any>(items: T[]): T[] => {

let result = [];

for (let i = items.length - 1; i >= 0; i--) {

result.push(items[i]);

}

return result;

}

<code>

workshops.de

106 of 116

Utility Types

of the React Library

workshops.de

107 of 116

FunctionComponent (before v18)

Utility Type which adds children prop to provided type of props (note: This changed in the type definitions of React 18!)

interface ButtonProps {

variant?: string;

onPress: (event: Event) => void;

};

const Button: FunctionComponent<ButtonProps> = ({

children,

variant = 'solid',

onPress,

}) => (

<Wrapper variant={variant} onPress={onPress}>

<Title>{children}</Title>

</Wrapper>

);

‘children’ prop access is allowed.

<code>

workshops.de

108 of 116

FunctionComponent (v18)

Utility Type which adds children prop to provided type of props (note: This changed in the types of React 18!)

import { ReactNode } from 'react'

interface ButtonProps {

variant?: string;

onPress: (event: Event) => void;

children: ReactNode

};

const Button: ButtonProps = ({

children,

variant = 'solid',

onPress,

}) => (

...

);

‘children’ prop access is allowed.

<code>

workshops.de

109 of 116

FunctionComponent (before v18)

Interface FunctionComponent in node_modules/@types/react/index.d.ts

interface FunctionComponent<P = {}> {

(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;

propTypes?: WeakValidationMap<P>;

contextTypes?: ValidationMap<any>;

defaultProps?: Partial<P>;

displayName?: string;

}

type FC<P = {}> = FunctionComponent<P>;

shorter name for the same type

<code>

workshops.de

110 of 116

FunctionComponent (v18)

Interface FunctionComponent in node_modules/@types/react/index.d.ts

interface FunctionComponent<P = {}> {

(props: P, context?: any): ReactElement<any, any> | null;

propTypes?: WeakValidationMap<P>;

contextTypes?: ValidationMap<any>;

defaultProps?: Partial<P>;

displayName?: string;

}

type FC<P = {}> = FunctionComponent<P>;

shorter name for the same type

<code>

workshops.de

111 of 116

Type useState hook

Initial value does not give enough information for a strong type

const [items , setItems] = useState<string[]>([]);

<code>

workshops.de

112 of 116

Tips

workshops.de

113 of 116

Hint

Press F8 in VSCode to jump from type error to type error to fix them.

workshops.de

114 of 116

Hint

Don’t try to type everything perfectly right from the start.

It’s ok to have some curly underlines

workshops.de

115 of 116

workshops.de

116 of 116

We teach.

workshops.de