Runtime TypeScript helpers that actually protect you when it matters most.
Why I Built Typetify: A Type-Safe Alternative to Lodash
TL;DR: I built Typetify — a zero-dependency utility library for TypeScript that provides runtime safety, not just compile-time types. Think Lodash, but TypeScript-first.
npm install typetify
The Problem with Lodash + TypeScript
Lodash is great. I've used it for years. But when you add TypeScript to the mix, something feels... off.
Example: The _.pick() Trap
import _ from 'lodash'
const user = {
id: 1,
name: 'John',
email: '[email protected]',
password: 'secret123'
}
// TypeScript says this is fine 🤷
const safe = _.pick(user, ['id', 'name', 'emial']) // Typo!
// ^^^^^^
// Runtime: { id: 1, name: 'John', emial: undefined }
// No error, no warning, just silent failure
TypeScript can't catch this because Lodash's types are too permissive. The keys are typed as string[], not the actual keys of the object.
Example: The _.isString() Trap
function processValue(value: unknown) {
if (_.isString(value)) {
return value.toUpperCase()
// ^^^^^ TS Error: Object is of type 'unknown'
}
}
Lodash's type guards don't narrow types properly. You get runtime safety, but TypeScript still doesn't trust the check.
The Solution: TypeScript-First Design
Typetify solves these issues by being designed for TypeScript, not retrofitted to it.
Type-Safe pick()
import { pick } from 'typetify/object'
const user = {
id: 1,
name: 'John',
email: '[email protected]',
password: 'secret123'
}
const safe = pick(user, ['id', 'name'])
// Type: { id: number; name: string }
// This won't compile:
const invalid = pick(user, ['id', 'emial'])
// ^^^^^^^ TS Error: 'emial' is not a key of user
The keys are actually type-checked. No typos, no silent failures.
Proper Type Narrowing
import { isString } from 'typetify/guards'
function processValue(value: unknown) {
if (isString(value)) {
return value.toUpperCase() // ✅ TypeScript knows it's a string
}
}
Type guards that actually work with TypeScript's control flow analysis.
5 Real-World Use Cases
1. API Response Validation
import { hasKeys, awaitTo } from 'typetify'
async function fetchUser(id: string) {
const [error, response] = await awaitTo(fetch(`/api/users/${id}`))
if (error) return { error: 'Network error' }
const data = await response.json()
// Runtime validation with type safety
if (!hasKeys(data, ['id', 'name', 'email'])) {
return { error: 'Invalid response' }
}
// TypeScript now knows data has these keys
return { data }
}
2. Error Handling Without try/catch
import { awaitTo, retry, withTimeout } from 'typetify/async'
async function fetchWithRetry(url: string) {
const [error, data] = await awaitTo(
retry(
() => withTimeout(fetch(url), 5000),
{ attempts: 3, delay: 1000 }
)
)
if (error) {
console.error('Failed after retries:', error)
return null
}
return data
}
No more nested try/catch blocks. Clean, readable error handling.
3. Form Data Processing
import { parseNumber, parseBoolean, compact, defaults } from 'typetify/input'
function processFormData(formData: FormData) {
return {
age: parseNumber(formData.get('age')), // number | undefined
newsletter: parseBoolean(formData.get('newsletter')), // boolean
tags: compact(formData.getAll('tags')), // string[]
bio: defaults(formData.get('bio'), 'No bio provided'), // string
}
}
Parse external data safely with proper TypeScript types.
4. Filtering Arrays
import { isDefined } from 'typetify/core'
// Problem: TypeScript doesn't narrow this
const items = [1, null, 2, undefined, 3]
const numbers = items.filter(x => x != null) // (number | null | undefined)[]
// Solution: Proper type guard
const numbers = items.filter(isDefined) // number[] ✅
5. Safe JSON Parsing
import { safeJsonParse } from 'typetify/input'
const result = safeJsonParse(jsonString)
if (result.ok) {
console.log(result.data.name) // Type-safe access
} else {
console.error(result.error) // Handle error
}
// No try/catch needed
The Design Philosophy
1. Runtime First
Types are great, but they disappear at runtime. Typetify gives you both.
import { assert } from 'typetify/core'
function getUser(id: string) {
const user = findUser(id) // User | null
assert(user, `User ${id} not found`)
// TypeScript now knows user is User (not null)
return user.name // Safe!
}
2. No Magic
Every function does exactly what it says. No hidden behavior, no gotchas.
import { pipe } from 'typetify/flow'
const result = pipe(
5,
n => n * 2, // 10
n => n + 1, // 11
n => `Result: ${n}` // 'Result: 11'
)
Simple composition. No magic.
3. Tree-Shakable
Only bundle what you use.
// Import specific functions
import { pick } from 'typetify/object'
import { retry } from 'typetify/async'
// Or import from specific modules
import * as object from 'typetify/object'
Your bundler will only include what you import.
4. Zero Dependencies
No bloat. No supply chain risks. Just pure TypeScript.
Comparing to Alternatives
| Feature | Lodash | Ramda | Typetify |
|---|---|---|---|
| TypeScript-first | ❌ | ❌ | ✅ |
| Runtime safety | ❌ | ❌ | ✅ |
| Type narrowing | ❌ | ❌ | ✅ |
| Zero dependencies | ❌ | ✅ | ✅ |
| Tree-shakable | ⚠️ Partial | ✅ | ✅ |
| Modern syntax | ❌ | ⚠️ | ✅ |
| Active maintenance | ⚠️ Slowing | ✅ | ✅ |
The Complete Feature Set
Typetify includes 18 modules covering:
Core -isDefined,assert,noop,identity
Guards -isString,isNumber,isObject,hasKey
Object -pick,omit,mapObject,get,set
Async -awaitTo,retry,debounce,throttle
Collection -unique,groupBy,partition,chunk
Input -safeJsonParse,parseNumber,parseBoolean
Flow -pipe,tap,match,tryCatch
String - String manipulation utilities
Math - Math utilities
Result - Result type pattern
Iterator - Iterator utilities
Decorator - TypeScript decorators
Logic - Logic utilities
Narrowing - Advanced type narrowing
Schema - Schema validation
DX -debug,invariant,measure,todo
Typed - Type utilities and branded types
Fn - Function utilities
Getting Started
npm install typetify
import { isDefined, pick, awaitTo } from 'typetify'
// Or use the Lodash-style _ namespace
import { _ } from 'typetify'
const safe = _.pick(user, ['id', 'name'])
What's Next?
I'd love to hear your feedback! Some areas I'm exploring:
- 🔍 More schema validation utilities (like Zod-lite)
- 🎯 Performance benchmarks vs Lodash/Ramda
- 📦 Plugin system for custom utilities
- 🧪 More real-world examples and recipes
Try It Out
🔗 GitHub: github.com/CodeSenior/typetify
📦 npm: npmjs.com/package/typetify
📚 Docs: typetify.hosby.io
Give it a try and let me know what you think! Stars ⭐ on GitHub are always appreciated.
Join the Discussion
What utility functions do you wish existed in TypeScript? Drop a comment below! 👇
P.S. We hit 477 downloads in the first 48 hours! 🚀 Thank you to everyone who's trying it out.