Type-safe path builder with automatic parameter extraction
npm install @khvostpola/pathy


Type-safe path builder with automatic parameter extraction for TypeScript.
- Type-safe — Automatic parameter extraction from path templates
- Zero dependencies — Lightweight and fast
- Dual format — ESM and CommonJS support
- Flexible — Support for required, optional, and rest parameters
- RFC 3986 — Proper URL encoding
``bash`
npm install @khvostpola/pathy
`bash`
yarn add @khvostpola/pathy
`bash`
pnpm add @khvostpola/pathy
`typescript
import { createPath } from '@khvostpola/pathy'
const userPath = createPath('/users/:id')
userPath({ path: { id: '123' } })
// → "/users/123"
// TypeScript knows 'id' is required!
userPath({ path: {} })
// ❌ Type error: Property 'id' is missing
`
Creates a type-safe path builder function.
`typescript`
const apiPath = createPath('/users/:id', 'https://api.example.com')
apiPath({ path: { id: '1' } })
// → "https://api.example.com/users/1"
| Syntax | Type | Example |
|--------|------|---------|
| :param | Required | /users/:id → { id: string } |:param?
| | Optional | /users/:id? → { id?: string } |:param
| | Rest (array) | /files/:path → { path: string \| string[] } |
Adds typed query parameter support.
`typescript
type Filters = { page: number; sort?: string }
const listPath = createPath('/users').withQuery
listPath({ query: { page: 1, sort: 'name' } })
// → "/users?page=1&sort=name"
`
Access the original template string.
`typescript`
const userPath = createPath('/users/:id')
console.log(userPath.template) // "/users/:id"
Groups multiple paths into an organized object.
`typescript
const api = createPathsMap({
users: createPath('/users'),
user: createPath('/users/:id'),
userPosts: createPath('/users/:id/posts'),
})
api.users() // → "/users"
api.user({ path: { id: '5' } }) // → "/users/5"
`
Builds hierarchical paths automatically.
`typescript
const paths = createIndexedPathsMap({
index: 'api/v1',
users: {
index: 'users',
detail: ':id',
posts: ':id/posts',
},
})
paths.users.detail({ path: { id: '42' } }) // → "/api/v1/users/42"
paths.users.posts({ path: { id: '42' } }) // → "/api/v1/users/42/posts"
`
`typescript
type UserQuery = { includeProfile?: boolean }
const userPath = createPath('/users/:id').withQuery
userPath({
path: { id: '42' },
query: { includeProfile: true },
})
// → "/users/42?includeProfile=true"
`
`typescript
type SearchQuery = { tags: string[] }
const searchPath = createPath('/search').withQuery
searchPath({ query: { tags: ['typescript', 'nodejs'] } })
// → "/search?tags=typescript&tags=nodejs"
`
`typescript
const apiPath = createPath('/users/:id', 'https://api.prod.com')
// Override for specific call
apiPath({
path: { id: '1' },
baseURL: 'https://api.staging.com',
})
// → "https://api.staging.com/users/1"
`
`typescript
const filesPath = createPath('/files/:segments*')
filesPath({ path: { segments: ['folder', 'subfolder', 'file.txt'] } })
// → "/files/folder/subfolder/file.txt"
`
The library provides full TypeScript support with automatic type inference:
`typescript
const userPath = createPath('/users/:id/:action?')
// TypeScript infers: { id: string; action?: string }
userPath({ path: { id: '123' } }) // ✓ OK
userPath({ path: { id: '123', action: 'edit' } }) // ✓ OK
userPath({ path: {} }) // ✗ Error: 'id' is required
userPath({ path: { id: '123', foo: 'bar' } }) // ✗ Error: 'foo' doesn't exist
``
---
"Aportar, crear, crecer... y tomar Pola."