Object Utility Types
Object Utility Types in TypeScript wie Partial
, Required
, Record
und Pick
ermöglichen eine flexible und effiziente Manipulation von Objekttypen. Sie vereinfachen die Anpassung bestehender Typen, fördern die Wiederverwendbarkeit und erhöhen die Typsicherheit in komplexen Anwendungen. Durch den gezielten Einsatz dieser Utilities lassen sich Schnittstellen präzise modellieren und der Entwicklungsprozess deutlich optimieren.
Inhaltsverzeichnis
Einführung
TypeScript Object Utility Types sind vordefinierte, generische Typen, die es ermöglichen, neue Typen basierend auf bestehenden Objekttypen zu erstellen. Sie funktionieren wie “Werkzeuge” oder “Funktionen” auf Typebene, die bestehende Typen transformieren, modifizieren oder daraus neue Typen ableiten.
Warum Object Utility Types?
In der modernen JavaScript/TypeScript Entwicklung arbeitet man ständig mit komplexen Objekt-Strukturen. Öft benötigt man Variationen eines bestehenden Typs. Mal sollen alle Eigenschaften optional sein, mal nur bestimmte ausgewählt werden oder man möchte alle Eigenschaften als schreibgeschützt markieren. Ohne Object Utility Types müsste man diese Variationen manuell definieren.
Das würde zu Folgendem führen:
- Code-Duplikation
- Wartungsprobleme bei Änderungen des ursprünglichen Typs
- Inkonsistenzen zwischen verwandten Typen
- Erhöhter Aufwand bei der Typ-Definition
Mehrwert
Object Utility Types liefern also folgende kräftige Vorteile:
- Typ-Sicherheit: Sie stellen sicher, dass abgeleitete Typen automatisch konsistent bleiben, wenn sich der ursprüngliche Typ ändert.
- DRY-Prinzip: Einmal definierte Typen können in verschiedenen Variationen wiederverwendet werden.
- Wartbarkeit: Änderungen an Basis-Typen propagieren automatisch zu allen abgeleiteten Typen.
- Lesbarkeit: Der Code wird selbstdokumentierend, da die Intention durch den Utility Typ klar wird.
- Produktivität: Schnellere Entwicklung durch weniger manuelle Typ-Definition.
Object Utility Types
Partial<T>
- Alle Eigenschaften optional machen
Partial<T>
macht alle Eigenschaften eines Typs <T>
optional. Dies ist besonders nützlich, wenn man Updates oder partielle Daten verarbeiten muss.
Partial<T>
type Partial<T> = {
[P in keyof T]?: T[P]
};
Hier ein praktisches Beispiel.
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Normalen Benutzer erstellen
const user: User = {
id: 1,
name: "John",
email: "john@mail.com",
age: 30
};
// Neuen Benutzer auf Basis von 'User'
// mit weniger Eigenschaften erzeugen
const userPartial: Partial<User> = {
email: "new@mail.com"
};
// Ausgabe von beiden Objekten
console.log(user);
console.log(userPartial);
{ id: 1, name: 'John', email: 'john@mail.com', age: 30 }
{ email: 'new@mail.com' }
Hier ein weiteres Beispiel mit Verwendung in einer Funktion.
interface I_User {
id: number;
name: string;
email: string;
age: number;
active: boolean;
}
// Mit Partial einen Typ für Updates erstellen
type T_UserUpdate = Partial<I_User>;
// Ein Äquivalent zu T_UserUpdate (nur zum Zeigen)
type T_UserUpdateEquivalent = {
id?: number;
name?: string;
email?: string;
age?: string;
active?: boolean;
};
// User-Liste
const users: I_User[] = [
{
id: 1,
name: "John",
email: "john@mail.com",
age: 30,
active: true
},
{
id: 2,
name: "Tom",
email: "tom@mail.com",
age: 32,
active: false
},
{
id: 3,
name: "Alice",
email: "alice@mail.com",
age: 40,
active: true
}
];
// Hilfs-Funktion - Benutzer abrufen
function getUserById(userId: number): I_User | undefined {
return users.find(u => u.id === userId);
}
// Funktion zur Aktualisierung der Benutzer
function updateUser(userId: number, updates: T_UserUpdate): I_User {
// Hier kann man sicher sein, dass nur
// gültige User-Eigenschaften übergeben werden, aber
// sind alle optional
const existingUser = getUserById(userId);
return {
...existingUser,
...updates
};
}
// Verwendung
console.log(updateUser(1, { name: "Max" }));
console.log(updateUser(1, { email: "max@mail.com", age: 31 }));
console.log(updateUser(2, { active: true }));
console.log(updateUser(3, {}));
{ id: 1, name: 'Max', email: 'john@mail.com', age: 30, active: true }
{ id: 1, name: 'John', email: 'max@mail.com', age: 31, active: true }
{ id: 2, name: 'Tom', email: 'tom@mail.com', age: 34, active: true }
{
id: 3,
name: 'Alice',
email: 'alice@mail.com',
age: 40,
active: true
}
Required<T>
- Alle Eigenschaften verpflichtend machen
Required<T>
ist das Gegenteil von Partial<T>
und macht alle Eigenschaften eines Typs verpflichtend, auch wenn sie ursprünglich optional waren.
Required<T>
type Required<T> = {
[P in keyof T]-?: T[P]
};
Nun schauen wir uns die Funktionsweise an einem praktischen Beispiel an.
interface I_ApiConfig {
baseUrl?: string;
timeout?: number;
retries?: number;
headers?: Record<string, string>;
}
// Finale Konfiguration soll alle Werte haben
type T_ApiConfigFull = Required<I_ApiConfig>;
// Äquivalent zu T_ApiConfigFull (nur zum Zeigen)
type T_ApiConfigFullEquivalent = {
baseUrl: string;
timeout: number;
retries: number;
headers: Record<string, string>;
};
class ApiConfigBuilder {
private config: Partial<I_ApiConfig> = {};
setBaseUrl(url: string): this {
this.config.baseUrl = url;
return this;
}
setTimeout(ms: number): this {
this.config.timeout = ms;
return this;
}
setRetries(count: number): this {
this.config.retries = count;
return this;
}
setHeaders(headers: Record<string, string>): this {
this.config.headers = headers;
return this;
}
build(): Required<I_ApiConfig> {
if (!this.config.baseUrl) throw new Error("baseUrl is required");
if (this.config.timeout === undefined) throw new Error("timeout is required");
if (this.config.retries === undefined) throw new Error("retries is required");
if (!this.config.headers) throw new Error("headers is required");
return this.config as T_ApiConfigFull;
}
}
// Verwendung
const configOne = new ApiConfigBuilder()
.setBaseUrl("http://localhost:9000")
.setTimeout(5000)
.setRetries(3)
.setHeaders({ "Content-Type": "application/json" })
.build();
console.log(configOne);
try {
const configTwo = new ApiConfigBuilder()
.setBaseUrl("http://localhost:8000")
.setRetries(2)
.setHeaders({ "Content-Type": "application/json" })
.build();
} catch (error) {
console.log("Fehler:", error.message);
}
{
baseUrl: 'http://localhost:9000',
timeout: 5000,
retries: 3,
headers: { 'Content-Type': 'application/json' }
}
Fehler: timeout is required
In diesem Beispiel haben wir zwei Objekt vom Typ T_ApiConfigFull
definiert. Im ersten Objekt sind alle Felder vorhanden. Im zweiten Objekt wurde ein Feld nicht übergeben/gesetzt. Dies führt zu einem Fehler, das die Methode build()
vom Typ T_ApiConfigFull
(was gleich Required<I_ApiConfig>
ist) zurückgibt und vorher das Vorhandensein aller Felder prüft.
Schauen wir uns ein weiteres Beispiel an.
interface I_CreateUserInput {
name?: string;
email?: string;
password?: string;
}
/**
* Create user
* ---
* Nach Validierung und Verarbeitung
* sind alle Felder vorhanden.
* ---
* @returns {Required<I_CreateUserInput>}
*/
function createUser(input: I_CreateUserInput): Required<I_CreateUserInput> {
if (!input.name) throw new Error("Name is required");
if (!input.email) throw new Error("Email is required");
if (!input.password) throw new Error("Password is required");
return input as Required<I_CreateUserInput>;
}
const userOne = createUser({
name: "John",
email: "john@mail.com",
password: "12345"
});
console.log(userOne);
try {
const userTwo = createUser({
name: "Tom",
email: "tom@mail.com"
});
} catch (error) {
console.log("Fehler:", error.message);
}
{ name: 'John', email: 'john@mail.com', password: '12345' }
Fehler: Password is required
In diesem Beispiel erwartet die Funktion createUser()
ein Objekt mit allen Feldern, welche im Interface I_CreateUserInput
definiert sind. Andernfalls, wie im Fall von userTwo
, wird ein Fehler geworfen.
Readonly<T>
- Alle Eigenschaften schreibgeschützt machen
Readonly<T>
macht alle Eigenschaften eines Typs schreibgeschützt. Dies ist nützlich für unveränderliche Daten-Strukturen oder um versehentliche Modifikationen zu verhindern.
Readonly<T>
type Readonly<T> = {
readonly [P in keyof T]: T[P]
};
Beispiel 1
Schauen wir uns ein praktisches Beispiel an, das die Verwendung von Readonly<T>
verdeutlicht.
interface I_Product {
id: number;
name: string;
price: number;
category: string;
}
// Schreibgeschützte Version
type T_ProductReadonly = Readonly<I_Product>;
// Äquivalent zu T_ProductReadonly (als Beispiel)
type T_ProductReadonlyEquivalent = {
readonly id: number;
readonly name: string;
readonly price: number;
readonly category: string;
};
/**
* Fetch product
* ---
* @param {number} id - ID of the product
* ---
* @returns {T_ProductReadonly}
*/
function fetchProduct(id: number): T_ProductReadonly {
const product = {
id,
name: "Laptop",
price: 1099,
category: "Electronis"
};
return product;
}
const product = fetchProduct(1);
console.log(product);
// Versuch etwas zu ändern
// product.price = 999;
// Cannot assign to 'price' because it is a read-only property.
{ id: 1, name: 'Laptop', price: 1099, category: 'Electronis' }
Beispiel 2
Lasst uns ein weiteres, umfangreicheres Beispiel aufbauen und Readonly<T>
verwenden.
interface I_Product {
id: string;
name: string;
price: number;
inStock: boolean;
}
interface I_User {
id: string;
name: string;
email: string;
}
interface I_CartItem {
productId: string;
quantity: number;
}
interface I_AppState {
user: I_User | null;
products: I_Product[];
cart: I_CartItem[];
isLoading: boolean;
}
// Schreibgeschützte Version
type T_AppStateReadonly = Readonly<I_AppState>;
class Store {
private state: I_AppState = {
user: null,
products: [],
cart: [],
isLoading: false
};
/**
* Get current state
* ---
* @returns {T_AppStateReadonly}
*/
getState(): T_AppStateReadonly {
return this.state;
}
/**
* Set state
* ---
* @param newState - New state
*/
private setState(newState: Partial<I_AppState>): void {
this.state = { ...this.state, ...newState };
}
/**
* Set loading status
* ---
* @param {boolean} loading - New loading status
*/
setLoading(loading: boolean): void {
this.setState({ isLoading: loading });
}
/**
* Login user
* ---
* @param {I_User} user - User data
*/
loginUser(user: I_User): void {
this.setState({ user, isLoading: false });
}
/**
* Logout user
*/
logoutUser(): void {
this.setState({ user: null, cart: [] });
}
/**
* Load products
* ---
* @param {I_Product[]} products - Products to load
*/
loadProducts(products: I_Product[]): void {
this.setState({ products, isLoading: false });
}
/**
* Add to cart
* ---
* @param {string} productId - ID of the product
* @param {number} quantity - Quantity to add
*/
addToCart(productId: string, quantity: number = 1): void {
const existingItem = this.state.cart.find(i => i.productId === productId);
const newCart = existingItem
? this.state.cart.map(item =>
item.productId === productId
? { ...item, quantity: item.quantity + quantity }
: item
)
: [...this.state.cart, { productId, quantity }];
this.setState({ cart: newCart });
}
/**
* Remove from cart
* ---
* @param {string} productId - ID of the product to remove
*/
removeFromCart(productId: string): void {
const newCart = this.state.cart.filter(i => i.productId !== productId);
this.setState({ cart: newCart });
}
}
const store = new Store();
// Initialer Zustand
console.log("Initialer Zustand:", store.getState());
console.log("\n--- --- ---\n");
// Benutzer anmelden
store.setLoading(true);
store.loginUser({
id: "u_001",
name: "John",
email: "john@mail.com"
});
console.log("Nach Login:", store.getState());
console.log("\n--- --- ---\n");
// Produkte laden
store.setLoading(true);
store.loadProducts([
{ id: "p_001", name: "Laptop", price: 999, inStock: true },
{ id: "p_002", name: "Smartphone", price: 699, inStock: true },
{ id: "p_003", name: "Headphones", price: 149, inStock: false }
]);
console.log("Produkte geladen:", store.getState());
console.log("\n--- --- ---\n");
// Warenkorb Aktionen
store.addToCart("p_001");
store.addToCart("p_002", 2);
console.log("Im Warenkorb:", store.getState());
console.log("\n--- --- ---\n");
store.removeFromCart("p_002");
console.log("Neuer Warenkorb:", store.getState());
console.log("\n--- --- ---\n");
// Benutzer abmelden
store.logoutUser();
console.log("Nach Logout:", store.getState());
Initialer Zustand: { user: null, products: [], cart: [], isLoading: false }
--- --- ---
Nach Login: {
user: { id: 'u_001', name: 'John', email: 'john@mail.com' },
products: [],
cart: [],
isLoading: false
}
--- --- ---
Produkte geladen: {
user: { id: 'u_001', name: 'John', email: 'john@mail.com' },
products: [
{ id: 'p_001', name: 'Laptop', price: 999, inStock: true },
{ id: 'p_002', name: 'Smartphone', price: 699, inStock: true },
{ id: 'p_003', name: 'Headphones', price: 149, inStock: false }
],
cart: [],
isLoading: false
}
--- --- ---
Im Warenkorb: {
user: { id: 'u_001', name: 'John', email: 'john@mail.com' },
products: [
{ id: 'p_001', name: 'Laptop', price: 999, inStock: true },
{ id: 'p_002', name: 'Smartphone', price: 699, inStock: true },
{ id: 'p_003', name: 'Headphones', price: 149, inStock: false }
],
cart: [
{ productId: 'p_001', quantity: 1 },
{ productId: 'p_002', quantity: 2 }
],
isLoading: false
}
--- --- ---
Neuer Warenkorb: {
user: { id: 'u_001', name: 'John', email: 'john@mail.com' },
products: [
{ id: 'p_001', name: 'Laptop', price: 999, inStock: true },
{ id: 'p_002', name: 'Smartphone', price: 699, inStock: true },
{ id: 'p_003', name: 'Headphones', price: 149, inStock: false }
],
cart: [ { productId: 'p_001', quantity: 1 } ],
isLoading: false
}
--- --- ---
Nach Logout: {
user: null,
products: [
{ id: 'p_001', name: 'Laptop', price: 999, inStock: true },
{ id: 'p_002', name: 'Smartphone', price: 699, inStock: true },
{ id: 'p_003', name: 'Headphones', price: 149, inStock: false }
],
cart: [],
isLoading: false
}
Beispiel 3
Im nächten Beispiel bauen wir eine kleine Funktion zum Herstellen der Datenbank-Verbindung auf. Dies ist lediglich eine vereinfachte Version, die ebenfalls die Verwendung von Readonly<T>
demonstriert.
interface I_DatabaseConfig {
host: string;
port: number;
database: string;
ssl: boolean;
}
/**
* Create database connection
* ---
* @param {Readonly<I_DatabaseConfig>} config - Database configuration
*/
function createDatabaseConnection(config: Readonly<I_DatabaseConfig>) {
console.log(`Connecting to: ${config.host}:${config.port}`);
// Für Modifikation expliti ein neues Objekt erstellen
const newConfig = { ...config, port: 3007 };
return newConfig;
}
const conn = createDatabaseConnection({ host: "localhost", port: 3306, database: "my_db", ssl: true });
console.log(conn);
Connecting to: localhost:3306
{ host: 'localhost', port: 3007, database: 'my_db', ssl: true }
Pick<T, K>
- Bestimmte Eigenschaften auswählen
Pick<T, K>
erstellt einen neuen Typ, indem es nur die angegebenen Eigenschaften K
aus dem Typ T
auswählt.
Pick<T, K extends keyof T>
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
};
Beispiel 1
Zuerst werfen wir einen Blick auf ein einfaches Beispiel.
interface I_User {
id: number;
username: string;
email: string;
salary: number;
}
type T_UserLight = Pick<I_User, "id" | "username">;
const userFull: I_User = {
id: 1,
username: "john",
email: "john@mail.com",
salary: 50000
};
const userLight: T_UserLight = {
id: 2,
username: "tom"
};
console.log(userFull);
console.log("--- --- ---")
console.log(userLight);
{ id: 1, username: 'john', email: 'john@mail.com', salary: 50000 }
--- --- ---
{ id: 2, username: 'tom' }
In diesem Beispiel haben wir zwei Objekte (Benutzer). In einem Fall haben wir einen Benutzer vom Typ I_User
definiert. Dieses Objekt muss das gesamte Interface und entsprechend auch alle Felder implementieren. Im zweiten Fall definieren wir einen Benutzer vom Typ T_UserLight
. Hier müssen lediglich die beiden definierten Felder implementiert (vorhanden) sein.
Beispiel 2
Schauen wir uns die Funktionsweise anhand eines komplexeren Beispiels an. Wie bereits erwähnt, ermöglicht Pick<T, K>
nur bestimmte Felder eines bereits vorhandenen Typs auszuwählen.
interface I_User {
id: number;
username: string;
email: string;
password: string;
firstName: string;
lastName: string;
dateOfBirth: Date;
address: string;
phoneNumber: string;
createdAt: Date;
updatedAt: Date;
isActive: boolean;
role: "admin" | "moderator" | "user";
}
// Nur für Login benötigte Felder
type T_LoginCredentials = Pick<I_User, "username" | "password">;
// Äquivalent zu T_LoginCredentials (nur als Beispiel)
type T_LoginCredentialsEquivalent = {
username: string;
password: string;
};
// Für öffentliche Profile (ohne sensitive Daten)
type T_PublicProfile = Pick<I_User, "id" | "username" | "firstName" | "lastName">;
// Für Benutzer-Liste im Admin-Panel
type T_UserListItem = Pick<I_User, "id" | "username" | "email" | "isActive" | "role">;
// Mock-Datenbank
const usersDatabase: I_User[] = [
{
id: 1,
username: "john",
email: "john@example.com",
password: "secure123",
firstName: "John",
lastName: "Doe",
dateOfBirth: new Date("1990-01-01"),
address: "123 Main St",
phoneNumber: "555-1234",
createdAt: new Date("2020-01-01"),
updatedAt: new Date("2023-01-01"),
isActive: true,
role: "user"
},
{
id: 2,
username: "admin",
email: "admin@example.com",
password: "admin123",
firstName: "Admin",
lastName: "User",
dateOfBirth: new Date("1985-05-15"),
address: "456 Admin Ave",
phoneNumber: "555-5678",
createdAt: new Date("2019-01-01"),
updatedAt: new Date("2023-06-01"),
isActive: true,
role: "admin"
}
];
/**
* Authenticate user
* ---
* @param {string} username - Username
* @param {string} password - Password
* ---
* @returns {Promise<string>}
*/
async function authenticateUser(username: string, password: string): Promise<string> {
const user = usersDatabase.find(u => u.username === username && u.password === password);
if (!user) throw new Error("Invalid credentials");
return `token-for-${user.id}`;
}
/**
* Get user by ID
* ---
* @param {number} userId - ID of the user
* ---
* @returns {I_User}
*/
function getUserById(userId: number): I_User {
const user = usersDatabase.find(u => u.id === userId);
if (!user) throw new Error("User not found");
return user;
}
/**
* Login
* ---
* @param {T_LoginCredentials} credentials - Login credentials
* ---
* @returns {Promise<string>}
*/
async function login(credentials: T_LoginCredentials): Promise<string> {
// Hier sind nur username und password verfügbar
return authenticateUser(credentials.username, credentials.password);
}
/**
* Get user profile
* ---
* @param {number} userId - ID of the user
* ---
* @returns {T_PublicProfile}
*/
function getUserProfile(userId: number): T_PublicProfile {
const user = getUserById(userId);
// Explizite Auswahl verhindert versehentliche Preisgabe von Daten
return {
id: user.id,
username: user.username,
firstName: user.firstName,
lastName: user.lastName
};
}
/**
* Get active users
* ---
* @returns {T_UserListItem[]}
*/
function getActiveUsers(): T_UserListItem[] {
return usersDatabase
.filter(u => u.isActive)
.map(u => ({
id: u.id,
username: u.username,
email: u.email,
isActive: u.isActive,
role: u.role
}));
}
// Beispiel - Ausführung
async function runExample() {
try {
// Login (Beispiel)
const token = await login({
username: "john",
password: "secure123"
});
console.log("Token:", token);
console.log("\n--- --- ---\n");
// Profil abrufen (Beispiel)
const profile = getUserProfile(1);
console.log("User profile:", profile);
console.log("\n--- --- ---\n");
// Admin-Liste (Beispiel)
const activeUsers = getActiveUsers();
console.log("Active users:", activeUsers);
} catch (error) {
if (error instanceof Error) {
console.log("Fehler:", error.message);
} else {
console.log("Fehler:", error);
}
}
}
runExample();
--- --- ---
User profile: { id: 1, username: 'john', firstName: 'John', lastName: 'Doe' }
--- --- ---
Active users: [
{
id: 1,
username: 'john',
email: 'john@example.com',
isActive: true,
role: 'user'
},
{
id: 2,
username: 'admin',
email: 'admin@example.com',
isActive: true,
role: 'admin'
}
]
Beispiel 3
In diesem Beispiel wird wieder ein Basis-Interfaces definiert. Daraus werden unterschiedliche Typen gebildet, welche nur einen Ausschnitt an Eigenschaften des Basis-Interfaces führen und für unterschiedliche Zwecke verwendet werden.
interface I_ApiProduct {
id: number;
sku: string;
name: string;
description: string;
price: number;
cost: number;
inventory: number;
supplierId: number;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
}
// Für öffentliche API - ohne interne Informationen
type T_PublicProduct = Pick<I_ApiProduct, "id" | "name" | "description" | "price" | "isActive">;
// Für Inventar-Management
type T_InventoryItem = Pick<I_ApiProduct, "id" | "sku" | "name" | "inventory" | "isActive">;
// Für Einkauf
type T_PurchaseItem = Pick<I_ApiProduct, "id" | "name" | "cost" | "supplierId" | "inventory">;
// Mock-Datenbank
const productsDatabase: I_ApiProduct[] = [
{
id: 1,
sku: "prod_001",
name: "Premium Kopfhörer",
description: "Noise-Cancelling Köpfhörer mit exzellentem Klang",
price: 299.99,
cost: 120.50,
inventory: 150,
supplierId: 101,
isActive: true,
createdAt: new Date("2025-06-21"),
updatedAt: new Date("2025-06-22")
},
{
id: 2,
sku: "prod_002",
name: "Mechanische Tastatur",
description: "RGB-beleuchtete mechanische Tastatur",
price: 129.99,
cost: 45.80,
inventory: 75,
supplierId: 102,
isActive: true,
createdAt: new Date("2025-06-21"),
updatedAt: new Date("2025-06-22")
},
{
id: 3,
sku: "prod_003",
name: "Veraltetes Produkt",
description: "Dieses Produkt wird nicht mehr verkauft",
price: 49.99,
cost: 20.00,
inventory: 10,
supplierId: 103,
isActive: false,
createdAt: new Date("2022-11-05"),
updatedAt: new Date("2025-06-20")
}
];
/**
* Get all products
* ---
* @returns {I_ApiProduct[]}
*/
function getAllProducts(): I_ApiProduct[] {
return productsDatabase;
}
/**
* Get public products
* ---
* @returns {T_PublicProduct[]}
*/
function getPublicProducts(): T_PublicProduct[] {
const allProducts = getAllProducts();
return allProducts.map(product => ({
id: product.id,
name: product.name,
description: product.description,
price: product.price,
isActive: product.isActive
}));
}
/**
* Get inventory items
* ---
* @returns {T_InventoryItem[]}
*/
function getInventoryItems(): T_InventoryItem[] {
const allProducts = getAllProducts();
return allProducts.map(product => ({
id: product.id,
sku: product.sku,
name: product.name,
inventory: product.inventory,
isActive: product.isActive
}));
}
/**
* Get purchase items
* ---
* @returns {T_PurchaseItem[]}
*/
function getPurchaseItems(): T_PurchaseItem[] {
const allProducts = getAllProducts();
return allProducts
.filter(product => product.inventory < 100)
.map(product => ({
id: product.id,
name: product.name,
cost: product.cost,
supplierId: product.supplierId,
inventory: product.inventory
}));
}
// Ausführung
function runExample() {
try {
// Öffentliche Produkte abrufen
const publicProducts = getPublicProducts();
console.log("Öffentliche Produkte");
console.log(publicProducts);
console.log("--- --- ---");
// Inventar-Liste abrufen
const inventoryItems = getInventoryItems();
console.log("Inventar-Liste");
console.log(inventoryItems);
console.log("--- --- ---");
// Einkaufsliste abrufen
const purchaseItems = getPurchaseItems();
console.log("Einkaufsliste");
console.log(purchaseItems);
} catch (error) {
if (error instanceof Error) {
console.log("Fehler:", error.message);
} else {
console.log("Fehler:", error);
}
}
}
runExample();
Öffentliche Produkte
[
{
id: 1,
name: 'Premium Kopfhörer',
description: 'Noise-Cancelling Köpfhörer mit exzellentem Klang',
price: 299.99,
isActive: true
},
{
id: 2,
name: 'Mechanische Tastatur',
description: 'RGB-beleuchtete mechanische Tastatur',
price: 129.99,
isActive: true
},
{
id: 3,
name: 'Veraltetes Produkt',
description: 'Dieses Produkt wird nicht mehr verkauft',
price: 49.99,
isActive: false
}
]
--- --- ---
Inventar-Liste
[
{
id: 1,
sku: 'prod_001',
name: 'Premium Kopfhörer',
inventory: 150,
isActive: true
},
{
id: 2,
sku: 'prod_002',
name: 'Mechanische Tastatur',
inventory: 75,
isActive: true
},
{
id: 3,
sku: 'prod_003',
name: 'Veraltetes Produkt',
inventory: 10,
isActive: false
}
]
--- --- ---
Einkaufsliste
[
{
id: 2,
name: 'Mechanische Tastatur',
cost: 45.8,
supplierId: 102,
inventory: 75
},
{
id: 3,
name: 'Veraltetes Produkt',
cost: 20,
supplierId: 103,
inventory: 10
}
]