Skip to content

Type Safety ​

One of TypeGlot's core features is generating fully-typed TypeScript from your translation files. This eliminates runtime errors from typos and missing parameters.

Generated Code ​

When you run typeglot build, the compiler generates TypeScript functions for each translation key:

Input: locales/en.json ​

json
{
  "hello": "Hello",
  "welcome": "Welcome, {name}!",
  "items_count": "{count, plural, one {# item} other {# items}}"
}

Output: src/generated/i18n/messages.ts ​

typescript
// Auto-generated by @typeglot/compiler
// Do not edit manually

export function hello(): string {
  return messages['hello'] ?? 'Hello';
}

export function welcome(params: { name: string }): string {
  const template = messages['welcome'] ?? 'Welcome, {name}!';
  return formatMessage(template, params);
}

export function items_count(params: { count: number }): string {
  const template = messages['items_count'] ?? '{count, plural, one {# item} other {# items}}';
  return formatMessage(template, params);
}

export const m = { hello, welcome, items_count } as const;

Type Inference ​

Parameter Types ​

The compiler infers parameter types from the translation value:

PatternInferred Type
{name}string
{count, number}number
{count, plural, ...}number
{date, date}Date (coming soon)

Compile-Time Errors ​

TypeScript catches errors at compile time:

typescript
import { m } from './generated/i18n';

// ✅ Correct usage
m.welcome({ name: 'Alice' });

// ❌ Compile error: Property 'naam' does not exist
m.welcome({ naam: 'Alice' });

// ❌ Compile error: Property 'name' is missing
m.welcome({});

// ❌ Compile error: Expected 1 argument, but got 0
m.welcome();

// ❌ Compile error: Type 'number' is not assignable to type 'string'
m.welcome({ name: 42 });

Autocomplete ​

Your IDE provides full autocomplete for:

  1. Translation keys — Type m. and see all available translations
  2. Parameters — Type { } and see required parameters
  3. Documentation — JSDoc comments show the default value
typescript
m.wel// IDE suggests: welcome
m.welcome({ n// IDE suggests: name

The m Object ​

All translation functions are exported both individually and as part of the m object:

typescript
// Individual imports
import { hello, welcome } from './generated/i18n';

// Or use the m object (recommended)
import { m } from './generated/i18n';

// Both work the same
hello() === m.hello();
welcome({ name: 'Alice' }) === m.welcome({ name: 'Alice' });

The m object is typed with as const, providing:

  • Autocomplete for all keys
  • Type safety for all parameters
  • Immutability guarantees

Locale Switching ​

The generated code supports runtime locale switching:

typescript
import { setLocale, getLocale, loadMessages, m } from './generated/i18n';
import * as es from './generated/i18n/es';
import * as fr from './generated/i18n/fr';

// Check current locale
console.log(getLocale()); // 'en'

// Switch to Spanish
setLocale('es');
loadMessages(es.messages);

console.log(m.hello()); // 'Hola'

// Switch to French
setLocale('fr');
loadMessages(fr.messages);

console.log(m.hello()); // 'Bonjour'

Strict Mode ​

For maximum type safety, the generated code uses strict TypeScript options:

  • noUncheckedIndexedAccess — Catches undefined access
  • noImplicitAny — Requires explicit types
  • strictNullChecks — Catches null/undefined issues

Best Practices ​

1. Keep Generated Files in Git ​

Commit the generated files so your CI/CD doesn't need to run the compiler:

gitignore
# Don't ignore generated i18n files
!src/generated/i18n/

2. Add a Pre-commit Hook ​

Ensure translations are always up-to-date:

json
// package.json
{
  "scripts": {
    "precommit": "typeglot build && git add src/generated/i18n"
  }
}

3. Use Strict TypeScript Config ​

Ensure your tsconfig.json has strict mode enabled:

json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true
  }
}

Released under the MIT License.