Extending nanofaker
Learn how to extend nanofaker with custom data, locales, and functionality to fit your specific needs.
Custom Data Arrays
Add custom data to existing categories:
ts
import { faker } from 'nanofaker'
// Extend with custom data
const customFaker = {
...faker,
person: {
...faker.person,
// Add custom method
superheroName: () => {
const superheroes = [
'Superman',
'Batman',
'Wonder Woman',
'Spider-Man',
'Iron Man',
]
return superheroes[Math.floor(Math.random() * superheroes.length)]
},
},
}
console.log(customFaker.person.superheroName()) // "Batman"
Custom Locales
Create your own locale with complete data:
ts
import type { LocaleDefinition } from 'nanofaker'
import { faker } from 'nanofaker'
const customLocale: LocaleDefinition = {
title: 'Custom English',
person: {
firstName: ['Alex', 'Jordan', 'Taylor', 'Morgan', 'Casey'],
lastName: ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones'],
gender: ['Non-binary', 'Agender', 'Genderfluid'],
jobTitle: ['DevRel Engineer', 'Growth Hacker', 'Data Scientist'],
prefix: ['Mx.', 'Dr.', 'Prof.'],
suffix: ['PhD', 'MD', 'Esq.'],
},
address: {
street: ['Innovation Drive', 'Tech Boulevard', 'Startup Lane'],
city: ['Silicon Valley', 'Austin', 'Seattle'],
state: ['California', 'Texas', 'Washington'],
country: ['United States', 'Canada', 'United Kingdom'],
zipCode: ['94025', '78701', '98101'],
direction: ['North', 'South', 'East', 'West'],
},
// ... add all other required categories
}
// Register custom locale
const customFaker = faker.locale('custom' as any)
// Note: TypeScript will show an error, but it will work at runtime
Custom Categories
Add entirely new categories:
ts
import { faker } from 'nanofaker'
interface ExtendedFaker {
fantasy: {
dragon: () => string
spell: () => string
kingdom: () => string
}
}
const extendedFaker = faker as any as ExtendedFaker
extendedFaker.fantasy = {
dragon: () => {
const dragons = ['Smaug', 'Drogon', 'Toothless', 'Falkor']
return dragons[Math.floor(Math.random() * dragons.length)]
},
spell: () => {
const spells = ['Fireball', 'Ice Storm', 'Lightning Bolt']
return spells[Math.floor(Math.random() * spells.length)]
},
kingdom: () => {
const kingdoms = ['Gondor', 'Winterfell', 'Narnia']
return kingdoms[Math.floor(Math.random() * kingdoms.length)]
},
}
console.log(extendedFaker.fantasy.dragon()) // "Smaug"
console.log(extendedFaker.fantasy.spell()) // "Fireball"
Wrapper Functions
Create utility functions around nanofaker:
ts
import { faker } from 'nanofaker'
// Full address generator
function generateFullAddress() {
return {
street: faker.address.street(),
city: faker.address.city(),
state: faker.address.state(),
country: faker.address.country(),
zipCode: faker.address.zipCode(),
}
}
// Complete user profile
function generateUserProfile() {
return {
personal: {
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
phone: faker.phone.number(),
},
address: generateFullAddress(),
preferences: {
favoriteFood: faker.food.dish(),
favoriteSport: faker.sport.sport(),
favoriteMusic: faker.music.genre(),
},
}
}
const user = generateUserProfile()
Custom Formatters
Create formatters for specific data patterns:
ts
import { faker } from 'nanofaker'
// Credit card formatter
function generateCreditCard() {
const cardNumber = Array.from({ length: 16 }, () =>
Math.floor(Math.random() * 10)).join('')
return {
number: cardNumber.match(/.{1,4}/g)?.join('-'),
holder: faker.person.fullName().toUpperCase(),
expiry: `${Math.floor(Math.random() * 12 + 1).toString().padStart(2, '0')}/${new Date().getFullYear() + Math.floor(Math.random() * 5)}`,
cvv: Math.floor(Math.random() * 900 + 100).toString(),
}
}
// Social security number formatter
function generateSSN() {
const area = Math.floor(Math.random() * 900 + 100)
const group = Math.floor(Math.random() * 90 + 10)
const serial = Math.floor(Math.random() * 9000 + 1000)
return `${area}-${group}-${serial}`
}
console.log(generateCreditCard())
// {
// number: "1234-5678-9012-3456",
// holder: "JOHN DOE",
// expiry: "12/2028",
// cvv: "123"
// }
Mixins Pattern
Create reusable mixins:
ts
import { faker } from 'nanofaker'
// Mixin for timestamps
const timestampMixin = {
createdAt: () => new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000),
updatedAt: () => new Date(),
}
// Mixin for IDs
const idMixin = {
uuid: () => crypto.randomUUID(),
shortId: () => Math.random().toString(36).substring(2, 9),
}
// Combine mixins
function createEntity() {
return {
...idMixin,
...timestampMixin,
name: faker.person.fullName(),
email: faker.internet.email(),
}
}
const entity = createEntity()
Plugin System
Create a simple plugin system:
ts
import { faker } from 'nanofaker'
type Plugin = (faker: any) => void
const plugins: Plugin[] = []
function registerPlugin(plugin: Plugin) {
plugins.push(plugin)
plugin(faker)
}
// Example plugin: Gaming data
const gamingPlugin: Plugin = (faker) => {
faker.gaming = {
gamertag: () => {
const adjectives = ['Epic', 'Dark', 'Shadow', 'Legendary']
const nouns = ['Warrior', 'Mage', 'Assassin', 'Hunter']
const adj = adjectives[Math.floor(Math.random() * adjectives.length)]
const noun = nouns[Math.floor(Math.random() * nouns.length)]
const num = Math.floor(Math.random() * 9999)
return `${adj}${noun}${num}`
},
achievement: () => {
const achievements = [
'First Blood',
'Triple Kill',
'Legendary',
'Victory Royale',
]
return achievements[Math.floor(Math.random() * achievements.length)]
},
}
}
// Register and use
registerPlugin(gamingPlugin)
console.log((faker as any).gaming.gamertag()) // "EpicWarrior1234"
Factory Pattern
Build complex objects with factories:
ts
import { faker } from 'nanofaker'
class UserFactory {
private overrides: Partial<User> = {}
with(overrides: Partial<User>): this {
this.overrides = { ...this.overrides, ...overrides }
return this
}
withLocale(locale: string): this {
faker.locale = locale as any
return this
}
build(): User {
return {
id: crypto.randomUUID(),
name: faker.person.fullName(),
email: faker.internet.email(),
city: faker.address.city(),
...this.overrides,
}
}
buildMany(count: number): User[] {
return Array.from({ length: count }, () => this.build())
}
}
// Usage
const user = new UserFactory()
.withLocale('es')
.with({ email: 'custom@example.com' })
.build()
const users = new UserFactory().buildMany(10)
Type-Safe Extensions
Extend nanofaker with full TypeScript support:
ts
import { faker } from 'nanofaker'
declare module 'nanofaker' {
interface Faker {
custom: {
uuid: () => string
slug: () => string
}
}
}
(faker as any).custom = {
uuid: () => crypto.randomUUID(),
slug: () => faker.person.lastName().toLowerCase().replace(/\s+/g, '-'),
}
// Now TypeScript knows about the custom methods
const id = faker.custom.uuid()
const slug = faker.custom.slug()
Internationalization Helpers
Create locale-aware helpers:
ts
import { faker } from 'nanofaker'
function generateLocalizedUser(locale: string) {
const originalLocale = faker.locale
faker.locale = locale as any
const user = {
name: faker.person.fullName(),
address: faker.address.city(),
food: faker.food.dish(),
}
faker.locale = originalLocale as any
return user
}
// Generate users in different locales
const users = ['en', 'es', 'fr', 'de'].map(locale => ({
locale,
...generateLocalizedUser(locale),
}))
Best Practices
1. Keep Extensions Separate
ts
// extensions/gaming.ts
// main.ts
import { faker } from 'nanofaker'
import { gamingExtension } from './extensions/gaming'
export const gamingExtension = {
gamertag: () => {
// Implementation
},
}
// extensions/finance.ts
export const financeExtension = {
creditCard: () => {
// Implementation
},
}
Object.assign(faker, { gaming: gamingExtension })
2. Document Your Extensions
ts
/**
* Gaming extension for nanofaker
*
* @example
* ```ts
* faker.gaming.gamertag() // "EpicWarrior1234"
* ```
*/
export const gamingExtension = {
// Implementation
}
3. Maintain Consistency
ts
// Good - Follows nanofaker patterns
faker.custom.methodName()
// Avoid - Different patterns
faker.CustomCategory.MethodName()
4. Test Your Extensions
ts
import { describe, expect, test } from 'bun:test'
import { faker } from 'nanofaker'
describe('Custom extensions', () => {
test('generates valid gamertag', () => {
const gamertag = (faker as any).gaming.gamertag()
expect(gamertag).toBeTruthy()
expect(typeof gamertag).toBe('string')
})
})
Extending nanofaker allows you to create domain-specific fake data generators that perfectly match your application's needs.