TypeScript Union & Intersection Types
Union und Intersection Types ermöglichen flexible Typkombinationen.
Union Types (|)
Ein Wert kann einer von mehreren Typen sein:
let value: string | number
value = "Hello" // ✅ OK
value = 42 // ✅ OK
value = true // ❌ Error
Function Parameters
function format(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase()
}
return value.toFixed(2)
}
format("hello") // "HELLO"
format(42.567) // "42.57"
Literal Union Types
type Status = "active" | "inactive" | "pending"
function setStatus(status: Status): void {
console.log(`Status: ${status}`)
}
setStatus("active") // ✅ OK
setStatus("deleted") // ❌ Error: not in union
Verwendung:
- State Management
- API Status Codes
- Enum-Alternativen
Arrays mit mehreren Typen
let mixed: (string | number)[] = ["Max", 25, "Anna", 30]
// NICHT verwechseln mit:
let tuple: [string, number] = ["Max", 25] // Feste Reihenfolge
Intersection Types (&)
Ein Wert muss alle Typen erfüllen:
interface Person {
name: string
age: number
}
interface Employee {
employeeId: number
department: string
}
type EmployeePerson = Person & Employee
const employee: EmployeePerson = {
name: "Max",
age: 25,
employeeId: 12345,
department: "IT"
}
Mixin Pattern
interface Loggable {
log(): void
}
interface Serializable {
serialize(): string
}
class User implements Loggable, Serializable {
constructor(public name: string) {}
log(): void {
console.log(this.name)
}
serialize(): string {
return JSON.stringify(this)
}
}
type LoggableSerializable = Loggable & Serializable
const user: LoggableSerializable = new User("Max")
user.log()
console.log(user.serialize())
Type Guards
Typprüfung zur Laufzeit:
typeof Guard
function process(value: string | number) {
if (typeof value === "string") {
// value ist hier Type: string
return value.toUpperCase()
}
// value ist hier Type: number
return value.toFixed(2)
}
instanceof Guard
class Dog {
bark() {
console.log("Woof!")
}
}
class Cat {
meow() {
console.log("Meow!")
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark()
} else {
animal.meow()
}
}
in Operator
interface Car {
drive(): void
}
interface Boat {
sail(): void
}
function move(vehicle: Car | Boat) {
if ("drive" in vehicle) {
vehicle.drive()
} else {
vehicle.sail()
}
}
Custom Type Guards
interface Fish {
swim(): void
}
interface Bird {
fly(): void
}
// Type Predicate
function isFish(animal: Fish | Bird): animal is Fish {
return (animal as Fish).swim !== undefined
}
function move(animal: Fish | Bird) {
if (isFish(animal)) {
animal.swim()
} else {
animal.fly()
}
}
Discriminated Unions
Union Types mit gemeinsamer Property:
interface Circle {
kind: "circle"
radius: number
}
interface Rectangle {
kind: "rectangle"
width: number
height: number
}
interface Triangle {
kind: "triangle"
base: number
height: number
}
type Shape = Circle | Rectangle | Triangle
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2
case "rectangle":
return shape.width * shape.height
case "triangle":
return (shape.base * shape.height) / 2
}
}
Vorteile:
- Exhaustiveness Checking
- Type Narrowing
- Keine Type Assertions nötig
Exhaustiveness Checking
type Shape = Circle | Rectangle | Triangle
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2
case "rectangle":
return shape.width * shape.height
case "triangle":
return (shape.base * shape.height) / 2
default:
const _exhaustive: never = shape
return _exhaustive
}
}
// Wenn Shape erweitert wird, gibt's Compiler-Error!
Union vs Intersection
Wann Union (|)
// "Entweder/Oder"
type PaymentMethod = "credit_card" | "paypal" | "bank_transfer"
// Mehrere mögliche Return Types
function getData(id: number): User | null {
// ...
}
// Flexible Parameter
function print(value: string | number | boolean): void {
console.log(value)
}
Wann Intersection (&)
// "Kombiniere beide"
type Admin = User & {
permissions: string[]
}
// Mixins
type Timestamped = {
createdAt: Date
updatedAt: Date
}
type User = {
name: string
email: string
}
type TimestampedUser = User & Timestamped
// Base Response
interface ApiResponse {
status: number
timestamp: Date
}
// Success Response
interface SuccessResponse<T> extends ApiResponse {
success: true
data: T
}
// Error Response
interface ErrorResponse extends ApiResponse {
success: false
error: string
code: string
}
// Union Type für Response
type Response<T> = SuccessResponse<T> | ErrorResponse
// Usage
async function fetchUser(id: number): Promise<Response<User>> {
try {
const data = await api.get(`/users/${id}`)
return {
success: true,
data,
status: 200,
timestamp: new Date()
}
} catch (error) {
return {
success: false,
error: error.message,
code: "USER_NOT_FOUND",
status: 404,
timestamp: new Date()
}
}
}
// Type Guard
const response = await fetchUser(1)
if (response.success) {
console.log(response.data.name) // Type: User
} else {
console.error(response.error) // Type: string
}📝 Quiz
Was ist der Unterschied zwischen Union (|) und Intersection (&)?
Tipps & Tricks
Type Narrowing mit Control Flow
function process(value: string | number | null) {
if (value === null) {
return // value ist null
}
if (typeof value === "string") {
return value.toUpperCase() // value ist string
}
return value.toFixed(2) // value ist number
}
Optional vs Union mit undefined
// Identisch
interface User {
name: string
email?: string
}
interface User {
name: string
email: string | undefined
}
// Aber unterschiedlich bei Objects:
const user1: User = { name: "Max" } // ✅ OK
const user2: User = { name: "Max", email: undefined } // ✅ OK
Branded Types
type UserId = string & { readonly brand: unique symbol }
type ProductId = string & { readonly brand: unique symbol }
function getUserById(id: UserId): User {
// ...
}
const userId = "123" as UserId
const productId = "456" as ProductId
getUserById(userId) // ✅ OK
getUserById(productId) // ❌ Error
Häufige Fehler
Fehler 1: Intersection mit widersprüchlichen Types
❌ FALSCH:
type Never = string & number // Type: never
// Kann nicht string UND number sein!
✅ RICHTIG:
type StringOrNumber = string | number // Union statt Intersection
Fehler 2: Type Guards vergessen
❌ FALSCH:
function process(value: string | number) {
return value.toUpperCase() // ❌ Error: number hat kein toUpperCase
}
✅ RICHTIG:
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase()
}
return value.toFixed(2)
}
Fehler 3: Discriminated Union ohne gemeinsames Field
❌ FALSCH:
interface Success {
data: string
}
interface Error {
error: string
}
type Result = Success | Error
function handle(result: Result) {
if (result.data) { // ❌ Error: data existiert nicht auf Error
// ...
}
}
✅ RICHTIG:
interface Success {
success: true
data: string
}
interface Error {
success: false
error: string
}
type Result = Success | Error
function handle(result: Result) {
if (result.success) {
console.log(result.data) // ✅ OK
} else {
console.log(result.error) // ✅ OK
}
}
Zusammenfassung
Du hast gelernt:
- ✅ Union Types (|) für ODER-Verknüpfungen
- ✅ Intersection Types (&) für UND-Verknüpfungen
- ✅ Type Guards für Runtime-Checks
- ✅ Discriminated Unions mit gemeinsamer Property
- ✅ Exhaustiveness Checking
- ✅ Custom Type Guards mit
is
Key Takeaways:
- Union = einer von mehreren
- Intersection = alle kombiniert
- Discriminated Unions für Type Safety
- Type Guards für Type Narrowing
- never Type für unmögliche Kombinationen
Nächste Schritte
Als Nächstes lernst du:
- Utility Types (Pick, Omit, Partial, etc.)
- Mapped Types
- Conditional Types
- Template Literal Types
Viel Erfolg! 🚀
Gut gemacht! 🎉
Du hast "TypeScript Union & Intersection Types" abgeschlossen
Artikel bewerten
Bitte einloggen um zu bewerten
Das könnte dich auch interessieren
TypeScript Basic Types - Primitive Datentypen
Lerne die grundlegenden Datentypen in TypeScript kennen: string, number, boolean, arrays, tuples und mehr.
TypeScript Generics - Wiederverwendbare Typen
Lerne Generics in TypeScript - das Werkzeug für flexible und wiederverwendbare Komponenten, Funktionen und Classes.
TypeScript Best Practices - Professioneller Code
Lerne die wichtigsten Best Practices für sauberen und wartbaren TypeScript Code. Naming, Patterns, Do's and Don'ts.