This guide helps you migrate from the Python azubiheft library to the TypeScript/Node.js version.
- π― Overview
- π Quick Migration
- π API Mapping
- π Code Examples
- π‘ Key Differences
- π οΈ Migration Strategies
- π§ͺ Testing Your Migration
The TypeScript version offers several advantages:
| Feature | Python Version | TypeScript Version |
|---|---|---|
| Type Safety | Runtime errors | Compile-time checking |
| IDE Support | Basic | Full IntelliSense, autocomplete |
| Performance | Good | Better (V8 engine) |
| Ecosystem | Python packages | npm ecosystem |
| Async/Await | Limited | Native, first-class |
| Web Integration | Complex | Seamless |
| Documentation | Basic | Comprehensive with examples |
The TypeScript version maintains 100% feature parity with the Python version while adding new capabilities:
- β All Python functionality preserved
- β Same API patterns and methods
- β Enhanced with TypeScript benefits
- β Additional features and utilities
Python:
pip install azubiheft-pythonTypeScript/Node.js:
npm install azubiheft-apiPython:
from azubiheft import Session, Entry
session = Session()
session.login('username', 'password')
entry = Entry(
date=datetime.now(),
message='Daily work',
time_spent='08:00',
entry_type=1
)
session.writeReports([entry])
session.logout()TypeScript:
import { Session, Entry, EntryType } from 'azubiheft-api';
const session = new Session();
await session.login({
username: 'username',
password: 'password'
});
const entry = new Entry(
new Date(),
'Daily work',
'08:00',
EntryType.BETRIEB
);
await session.writeReports([entry]);
await session.logout();- Async/Await: All operations are now asynchronous
- Object Parameters: Login uses object instead of positional parameters
- TypeScript Types: Strong typing with interfaces and enums
- Error Handling: Specific error types with type guards
| Python | TypeScript | Notes |
|---|---|---|
Session() |
Session() |
Same constructor |
Entry() |
Entry() |
Same constructor pattern |
TimeHelper |
TimeHelper |
Static methods, same functionality |
| Python Method | TypeScript Method | Changes |
|---|---|---|
login(username, password) |
login({ username, password }) |
Object parameter |
logout() |
logout() |
Now async |
isLoggedIn() |
isLoggedIn() |
Now async |
writeReport(...) |
writeReport(...) |
Now async |
writeReports(entries) |
writeReports(entries) |
Now async |
getReport(date) |
getReport(date) |
Now async |
deleteReport(date, entry_num) |
deleteReport(date, entryNumber) |
Now async |
getSubjects() |
getSubjects() |
Now async |
addSubject(name) |
addSubject(name) |
Now async |
deleteSubject(id) |
deleteSubject(id) |
Now async |
getReportWeekId(date) |
getReportWeekId(date) |
Now async |
get_art_id_from_text(name) |
getArtIdFromText(name) |
Now async, camelCase |
| Python | TypeScript | Changes |
|---|---|---|
Entry(date, message, time_spent, type) |
Entry(date, message, timeSpent, type) |
camelCase parameters |
entry.date |
entry.date |
Same |
entry.message |
entry.message |
Same |
entry.time_spent |
entry.timeSpent |
camelCase |
entry.type |
entry.type |
Same |
| N/A | entry.validate() |
New method |
| N/A | Entry.fromObject(data) |
New static method |
| N/A | entry.with(updates) |
New method |
| Python | TypeScript | Changes |
|---|---|---|
TimeHelper.dateTimeToString(date) |
TimeHelper.dateTimeToString(date) |
Same |
TimeHelper.getActualTimestamp() |
TimeHelper.getActualTimestamp() |
Same |
TimeHelper.timeDeltaToString(delta) |
TimeHelper.millisecondsToTimeString(ms) |
Different input type |
| N/A | TimeHelper.addTimeStrings(t1, t2) |
New method |
| N/A | TimeHelper.subtractTimeStrings(t1, t2) |
New method |
| N/A | TimeHelper.timeStringToMinutes(time) |
New method |
| N/A | TimeHelper.minutesToTimeString(mins) |
New method |
| N/A | TimeHelper.getISOWeek(date) |
New method |
| Python | TypeScript | Changes |
|---|---|---|
AuthError |
AuthError |
Same |
NotLoggedInError |
NotLoggedInError |
Same |
ValueTooLargeError |
ValueTooLargeError |
Same |
| N/A | ApiError |
New |
| N/A | ParseError |
New |
| N/A | NetworkError |
New |
| N/A | isAuthError() |
New type guard |
Python:
from azubiheft import Session, AuthError
session = Session()
try:
session.login('myuser', 'mypass')
print("Login successful!")
except AuthError as e:
print(f"Login failed: {e}")TypeScript:
import { Session, isAuthError } from 'azubiheft-api';
const session = new Session();
try {
await session.login({
username: 'myuser',
password: 'mypass'
});
console.log('Login successful!');
} catch (error) {
if (isAuthError(error)) {
console.log(`Login failed: ${error.message}`);
}
}Python:
from datetime import datetime, timedelta
from azubiheft import Session, Entry
session = Session()
session.login('user', 'pass')
entries = []
for i in range(5):
date = datetime.now() - timedelta(days=i)
entry = Entry(
date=date,
message=f'Work day {i+1}',
time_spent='08:00',
entry_type=1
)
entries.append(entry)
session.writeReports(entries)
session.logout()TypeScript:
import { Session, Entry, EntryType } from 'azubiheft-api';
const session = new Session();
await session.login({ username: 'user', password: 'pass' });
const entries = [];
for (let i = 0; i < 5; i++) {
const date = new Date();
date.setDate(date.getDate() - i);
const entry = new Entry(
date,
`Work day ${i + 1}`,
'08:00',
EntryType.BETRIEB
);
entries.push(entry);
}
await session.writeReports(entries);
await session.logout();Python:
from datetime import timedelta
from azubiheft import TimeHelper
# Time arithmetic
delta = timedelta(hours=8, minutes=30)
time_str = TimeHelper.timeDeltaToString(delta)
print(f"Time: {time_str}")TypeScript:
import { TimeHelper } from 'azubiheft-api';
// Time arithmetic
const totalTime = TimeHelper.addTimeStrings('04:30', '04:00');
console.log(`Time: ${totalTime}`); // "08:30"
// Convert between formats
const minutes = TimeHelper.timeStringToMinutes('08:30');
const backToString = TimeHelper.minutesToTimeString(minutes);Python:
import time
from azubiheft import Session, AuthError, NotLoggedInError
def login_with_retry(session, username, password, max_retries=3):
for attempt in range(max_retries):
try:
session.login(username, password)
return True
except AuthError:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
return FalseTypeScript:
import { Session, isAuthError, isNotLoggedInError } from 'azubiheft-api';
async function loginWithRetry(
session: Session,
credentials: { username: string; password: string },
maxRetries = 3
): Promise<boolean> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
await session.login(credentials);
return true;
} catch (error) {
if (isAuthError(error)) {
if (attempt === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 2 ** attempt * 1000));
} else {
throw error;
}
}
}
return false;
}Python (Synchronous):
# All operations are synchronous
session.login('user', 'pass')
reports = session.getReport(datetime.now())
session.writeReports(entries)TypeScript (Asynchronous):
// All operations are asynchronous
await session.login({ username: 'user', password: 'pass' });
const reports = await session.getReport(new Date());
await session.writeReports(entries);Python (Positional/Keyword):
session.login('username', 'password')
session.deleteReport(date, entry_number=1)TypeScript (Object/Named):
await session.login({ username: 'username', password: 'password' });
await session.deleteReport(date, 1);Python (Duck Typing):
# Runtime type checking
entry = Entry(
date="invalid-date", # Runtime error
message=123, # Runtime error
time_spent="25:00", # Runtime error
entry_type="invalid" # Runtime error
)TypeScript (Compile-time Checking):
// Compile-time type checking
const entry = new Entry(
"invalid-date", // β TypeScript error
123, // β TypeScript error
"25:00", // β Runtime validation error
"invalid" // β TypeScript error
);Python (Exception Types):
try:
session.login('user', 'pass')
except AuthError:
# Handle auth error
except Exception as e:
# Handle other errorsTypeScript (Type Guards):
try {
await session.login({ username: 'user', password: 'pass' });
} catch (error) {
if (isAuthError(error)) {
// Handle auth error with full type safety
} else if (isNotLoggedInError(error)) {
// Handle login state error
} else {
// Handle other errors
}
}Replace Python code line-by-line with TypeScript equivalents:
-
Convert imports:
from azubiheft import Session, Entry
β
import { Session, Entry } from 'azubiheft-api';
-
Add async/await:
session.login('user', 'pass')
β
await session.login({ username: 'user', password: 'pass' });
-
Update parameter styles:
Entry(date, message, time_spent, entry_type)
β
new Entry(date, message, timeSpent, entryType)
For large codebases, migrate incrementally:
-
Start with utilities:
- Migrate
TimeHelperusage first - Update date/time handling
- Test thoroughly
- Migrate
-
Migrate core logic:
- Convert
Sessionoperations - Update error handling
- Add type annotations
- Convert
-
Enhance with TypeScript features:
- Add interfaces for data structures
- Use enums for constants
- Implement type guards
Create compatibility wrappers for smooth transition:
// Python-like wrapper for easier migration
class PythonCompatSession {
private session = new Session();
login(username: string, password: string): Promise<void> {
return this.session.login({ username, password });
}
writeReport(date: Date, message: string, timeSpent: string, entryType: number): Promise<void> {
const entry = new Entry(date, message, timeSpent, entryType);
return this.session.writeReports([entry]);
}
}test-migration.ts:
import { Session, Entry, EntryType, TimeHelper } from 'azubiheft-api';
async function testMigration() {
console.log('Testing azubiheft-api migration...');
// Test TimeHelper (synchronous)
const dateStr = TimeHelper.dateTimeToString(new Date());
console.log('β
TimeHelper working:', dateStr);
// Test Entry creation
const entry = new Entry(new Date(), 'Test entry', '01:00', EntryType.BETRIEB);
entry.validate();
console.log('β
Entry creation working');
// Test Session (requires credentials)
if (process.env.AZUBIHEFT_USERNAME && process.env.AZUBIHEFT_PASSWORD) {
const session = new Session();
try {
await session.login({
username: process.env.AZUBIHEFT_USERNAME,
password: process.env.AZUBIHEFT_PASSWORD
});
console.log('β
Session login working');
const subjects = await session.getSubjects();
console.log('β
Subject fetching working:', subjects.length, 'subjects');
await session.logout();
console.log('β
Session logout working');
} catch (error) {
console.error('β Session test failed:', error.message);
}
}
console.log('Migration test completed!');
}
testMigration().catch(console.error);Create comparable scripts in both Python and TypeScript to verify identical behavior:
Python test:
from azubiheft import TimeHelper
from datetime import datetime
date = datetime(2024, 1, 15)
result = TimeHelper.dateTimeToString(date)
print(f"Python result: {result}")TypeScript test:
import { TimeHelper } from 'azubiheft-api';
const date = new Date('2024-01-15');
const result = TimeHelper.dateTimeToString(date);
console.log(`TypeScript result: ${result}`);Create comprehensive tests covering all migrated functionality:
import { describe, test, expect } from '@jest/globals';
import { Session, Entry, EntryType, TimeHelper } from 'azubiheft-api';
describe('Migration Compatibility', () => {
test('TimeHelper produces same results as Python', () => {
const date = new Date('2024-01-15');
const result = TimeHelper.dateTimeToString(date);
expect(result).toBe('20240115'); // Same as Python version
});
test('Entry validation works correctly', () => {
const entry = new Entry(new Date(), 'Test', '08:00', EntryType.BETRIEB);
expect(() => entry.validate()).not.toThrow();
});
// Add more tests...
});-
Environment Setup
- Node.js 16+ installed
- TypeScript configured
- azubiheft-api package installed
-
Code Migration
- Imports converted
- Async/await added to all session operations
- Parameter styles updated
- Error handling converted to type guards
-
Type Safety
- Added TypeScript types
- Used enums instead of magic numbers
- Implemented proper interfaces
-
Testing
- Created test scripts
- Verified identical behavior
- Added unit tests
- Tested error scenarios
-
Documentation
- Updated code comments
- Created migration notes
- Updated team documentation
The migration from Python to TypeScript provides significant benefits while maintaining full compatibility. The async/await pattern, enhanced type safety, and rich ecosystem make the TypeScript version ideal for modern development.
Key Benefits Achieved:
- β Type Safety: Catch errors at compile time
- β Better IDE Support: Full IntelliSense and autocomplete
- β Modern Async: Native Promise support
- β Rich Ecosystem: Access to npm packages
- β Enhanced Features: Additional utilities and helpers
Next Steps:
- Complete your migration using this guide
- Explore the advanced features
- Check out the comprehensive examples
- Join the community for support and tips
Need help with migration? Check our Troubleshooting Guide or create an issue!