Get Started with Kotlinify
Transform your TypeScript code with Kotlin's most powerful patterns in under 5 minutes
Installation
npm install kotlinify-tsOr with yarn, pnpm, or bun:
yarn add kotlinify-ts
pnpm add kotlinify-ts
bun add kotlinify-tsWhy Kotlinify?
See the power of functional programming patterns in action
❌ Without Kotlinify
// Nested, hard-to-follow logic
let data = fetchData();
if (data) {
data = data.filter(x => x.active);
console.log(`Processing ${data.length}`);
data = data.map(x => x.value);
metrics.record('processed', data.length);
return data;
}
return null;✅ With Kotlinify
// Clean, chainable, functional - ONE beautiful expression!
await asScope(fetchData())
.letOrNull(data => data?.filter(x => x.active))
.also(d => d && console.log(`Processing ${d.length}`))
.letOrNull(d => d?.map(x => x.value))
.also(d => d && metrics.record('processed', d.length))
.value();Core Patterns
Five powerful concepts that will transform your code
1. Scope Functions - Chain Operations Elegantly
Transform, configure, and observe values through a clean pipeline
import { asScope, apply } from 'kotlinify-ts';
// Transform data through a fluent pipeline - no intermediate variables!
const apiResponse = { data: { user: { name: "Alice", score: 85 } } };
const message = asScope(apiResponse)
.let(response => response.data.user)
.let(user => ({ ...user, grade: user.score >= 90 ? 'A' : 'B' }))
.let(graded => `${graded.name} earned a ${graded.grade}`)
.value();
console.log(message); // "Alice earned a B"
// Configure complex objects with beautiful chaining
const config = apply({} as any, cfg => {
cfg.apiUrl = process.env.API_URL;
cfg.timeout = 5000;
cfg.retries = 3;
cfg.headers = { 'Content-Type': 'application/json' };
});
// Track operations with side effects in a clean chain
// Works seamlessly with async data sources too
const processedData = await asScope(fetchData())
.let(data => data.filter(item => item.active))
.also(filtered => console.log(`Processing ${filtered.length} items`))
.let(items => items.map(item => item.value))
.also(values => metrics.record('items.processed', values.length))
.value();2. Null Safety - Handle Nullables Gracefully
Chain operations safely without endless null checks
import { asScope, letOrNull, applyOrNull, takeIf, takeUnless } from 'kotlinify-ts';
// Safely transform nullable values with elegant chaining
const userInput: string | null = getUserInput();
const result = asScope(userInput)
.letOrNull(input => input.trim())
.letOrNull(trimmed => trimmed.toLowerCase())
.letOrNull(normalized => normalizeText(normalized))
.value();
// Conditional value retention with fluent API
const validEmail = takeIf(email, e => e.includes('@') && e.includes('.'));
const nonEmptyList = takeUnless(items, list => list.length === 0);
// Configure objects only when non-null
const user = applyOrNull(findUserById(id), u => {
u.lastSeen = Date.now();
u.sessionCount++;
});3. Flow - Reactive Streams Made Simple
Build reactive applications with powerful stream processing
import { flowOf, flow, MutableStateFlow } from 'kotlinify-ts/flow';
// Create reactive data streams
const temperatureFlow = flowOf(20, 22, 25, 23, 21)
.map(celsius => celsius * 9/5 + 32)
.filter(fahrenheit => fahrenheit > 70)
.onEach(f => console.log(`Temperature: ${f}°F`));
await temperatureFlow.collect(temp => {
updateDisplay(temp);
});
// State management with reactive updates
const userState = new MutableStateFlow({ name: "Guest", loggedIn: false });
// Subscribe to state changes
userState
.map(user => user.name)
.distinctUntilChanged()
.collect(name => updateUIName(name));
// Update state triggers all collectors
userState.value = { name: "Alice", loggedIn: true };4. Sequences - Lazy Evaluation for Performance
Process large datasets efficiently with lazy evaluation
import { asSequence, generateSequence } from 'kotlinify-ts/sequences';
// Process large datasets lazily
const bigData = asSequence(hugeArray)
.filter(item => item.isValid)
.map(item => item.normalize())
.take(100) // Only processes first 100 valid items
.toArray();
// Generate infinite sequences
const fibonacci = generateSequence([0, 1], ([a, b]) => [b, a + b])
.map(([a]) => a)
.take(10)
.toArray(); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
// Efficient grouping and aggregation
const groups = asSequence(transactions)
.groupBy(t => t.category); // Returns Map<string, Transaction[]>
const summary = Array.from(groups).map(([category, items]) => ({
category,
total: asSequence(items).sumBy(t => t.amount),
count: items.length
}));5. Monads - Type-Safe Error Handling
Replace try-catch blocks with composable error handling
import { tryCatch, Success, Failure } from 'kotlinify-ts/monads';
import { Some, None, fromNullable } from 'kotlinify-ts/monads';
// Elegant error handling
const result = tryCatch(() => JSON.parse(jsonString))
.map(data => data.user)
.map(user => user.email)
.fold(
error => `Failed: ${error.message}`,
email => `User email: ${email}`
);
// Null-safe operations with Option
const userOption = fromNullable(findUser(id))
.filter(u => u.isActive)
.map(u => u.profile)
.getOrElse({ name: "Anonymous", avatar: "default.png" });
// Chain fallible operations
const processed = await tryCatchAsync(() => fetchData())
.flatMap(data => tryCatch(() => validateData(data)))
.map(valid => transformData(valid))
.recover(error => getDefaultData());The Power of Chainable APIs
Enable fluent, readable code with method chaining
Why Chaining Matters
The real value of kotlinify-ts isn't just the individual functions - it's the ability to chain them into expressive, self-documenting pipelines that eliminate intermediate variables and make your intent crystal clear.
Clean, Functional Pipelines
import { asScope } from 'kotlinify-ts';
// Transform any value through a pipeline
const result = asScope(getValue())
.let(v => process(v))
.also(v => log(v))
.let(v => format(v))
.value();
// No intermediate variables
// No nested callbacks
// Just beautiful, flowing code✅ Benefits
- • Fluent, readable pipelines
- • No intermediate variables
- • Clear data flow
- • Easy refactoring
- • Self-documenting code
🎯 Perfect For
- • Data transformations
- • Object configuration
- • API response processing
- • Complex business logic
- • React component props
Zero Prototype Pollution
Use asScope() for chainable scope functions, or import standalone utilities. No global modifications, no side effects - just clean, explicit imports.
Real-World Example
See how kotlinify-ts transforms a typical data processing pipeline:
import 'kotlinify-ts';
// Process API data with beautiful chaining and error handling
async function processUserData(userId: string) {
return await fetchUser(userId)
.tryCatch()
.map(user => ({
...user,
transactions: user.transactions
.asSequence()
.filter(t => t.status === 'completed')
.map(t => ({ ...t, amount: t.amount * exchangeRate }))
.sortedBy(t => t.date)
.take(100)
.toArray()
}))
.also(processed => logger.info('User processed', { userId }))
.map(user => enrichUserData(user))
.fold(
error => {
logger.error('Failed to process user', { userId, error });
return getDefaultUser();
},
user => {
cache.set(userId, user);
return user;
}
);
}
// Stream real-time updates
const priceUpdates = flowOf(...initialPrices)
.flatMapLatest(price =>
subscribeToUpdates(price.symbol)
.map(update => ({ ...price, ...update }))
)
.distinctUntilChangedBy(p => p.value)
.throttle(100)
.onEach(price => updateUI(price))
.catch(error => handleStreamError(error));
await priceUpdates.collect(price => {
broadcastToClients(price);
});What Developers Are Saying
"Finally, I can write TypeScript that's as expressive as my Kotlin code. The scope functions alone have transformed how I structure my React components."
— Senior Full-Stack Developer
"The Flow API is incredible for handling WebSocket streams. It's like RxJS but with a much cleaner API."
— Real-time Applications Developer
"Result and Option monads have eliminated 90% of our null pointer exceptions. Our error handling is now type-safe and composable."
— Tech Lead
Ready to Transform Your Code?
Deep Dive: Scope Functions
Master let, apply, also, run, and with for elegant data transformations
Build with Flow
Create reactive applications with powerful stream processing
Optimize with Sequences
Process large datasets efficiently with lazy evaluation
Handle Errors Functionally
Replace try-catch with composable Option, Either, and Result types
Join the Community
Start Writing Better TypeScript Today
Join thousands of developers who are already using kotlinify-ts to write cleaner, more maintainable TypeScript code with the power of Kotlin's best patterns.