@khvostpola/pathy
v0.1.1
Published
Type-safe path builder with automatic parameter extraction
Maintainers
Readme
@khvostpola/pathy
Type-safe path builder with automatic parameter extraction for TypeScript.
Features
- 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
Installation
npm install @khvostpola/pathyyarn add @khvostpola/pathypnpm add @khvostpola/pathyQuick Start
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 missingAPI
createPath(template, baseURL?)
Creates a type-safe path builder function.
const apiPath = createPath('/users/:id', 'https://api.example.com')
apiPath({ path: { id: '1' } })
// → "https://api.example.com/users/1"Parameter Syntax
| Syntax | Type | Example |
|--------|------|---------|
| :param | Required | /users/:id → { id: string } |
| :param? | Optional | /users/:id? → { id?: string } |
| :param* | Rest (array) | /files/:path* → { path: string \| string[] } |
.withQuery<Q>()
Adds typed query parameter support.
type Filters = { page: number; sort?: string }
const listPath = createPath('/users').withQuery<Filters>()
listPath({ query: { page: 1, sort: 'name' } })
// → "/users?page=1&sort=name".template
Access the original template string.
const userPath = createPath('/users/:id')
console.log(userPath.template) // "/users/:id"createPathsMap(paths)
Groups multiple paths into an organized object.
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"createIndexedPathsMap(config)
Builds hierarchical paths automatically.
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"Advanced Examples
Combining path and query params
type UserQuery = { includeProfile?: boolean }
const userPath = createPath('/users/:id').withQuery<UserQuery>()
userPath({
path: { id: '42' },
query: { includeProfile: true },
})
// → "/users/42?includeProfile=true"Array query params
type SearchQuery = { tags: string[] }
const searchPath = createPath('/search').withQuery<SearchQuery>()
searchPath({ query: { tags: ['typescript', 'nodejs'] } })
// → "/search?tags=typescript&tags=nodejs"BaseURL override
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"Rest parameters
const filesPath = createPath('/files/:segments*')
filesPath({ path: { segments: ['folder', 'subfolder', 'file.txt'] } })
// → "/files/folder/subfolder/file.txt"TypeScript Support
The library provides full TypeScript support with automatic type inference:
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 existLicense
"Aportar, crear, crecer... y tomar Pola."
