Skip to main content

Function Signature

function defineAchievements<const T extends ReadonlyArray<AchievementDef<string>>>(
  definitions: T
): T
Define an array of achievement definitions with full type inference. IDs are inferred as literal types, enabling autocomplete and type safety throughout your application.

Parameters

definitions
ReadonlyArray<AchievementDef<string>>
required
Array of achievement definitions. Each definition must include id, label, and description.

Returns

definitions
T
The same array, with full type inference preserved. IDs are inferred as literal string types.

Example

import { defineAchievements } from '@achievements-manager/core';

const definitions = defineAchievements([
  {
    id: 'first-login',
    label: 'Welcome!',
    description: 'Log in for the first time',
  },
  {
    id: 'complete-profile',
    label: 'Profile Complete',
    description: 'Fill out all profile fields',
    maxProgress: 5,
  },
  {
    id: 'visit-all-pages',
    label: 'Explorer',
    description: 'Visit all pages in the app',
    maxProgress: 10,
  },
  {
    id: 'secret-easter-egg',
    label: '???',
    description: 'Find the hidden easter egg',
    hidden: true,
  },
] as const);

// Extract the ID union type
type AchievementId = typeof definitions[number]['id'];
// Result: 'first-login' | 'complete-profile' | 'visit-all-pages' | 'secret-easter-egg'

Type Inference

The defineAchievements function uses TypeScript’s const type parameter to preserve literal types:
// Without defineAchievements:
const definitions = [
  { id: 'first-login', label: 'Welcome!', description: '...' },
];
// Type of id: string ❌

// With defineAchievements:
const definitions = defineAchievements([
  { id: 'first-login', label: 'Welcome!', description: '...' },
]);
// Type of id: 'first-login' ✅
This enables:
  • Autocomplete for achievement IDs throughout your app
  • Type errors if you reference a non-existent achievement
  • Refactoring safety when renaming achievement IDs

Deriving the ID Type

You can extract a union type of all achievement IDs:
const definitions = defineAchievements([
  { id: 'first-login', label: 'Welcome!', description: '...' },
  { id: 'complete-profile', label: 'Profile', description: '...' },
]);

type AchievementId = typeof definitions[number]['id'];
// Result: 'first-login' | 'complete-profile'

// Use in your application:
function unlockAchievement(id: AchievementId) {
  engine.unlock(id); // Type-safe!
}

unlockAchievement('first-login'); // ✅
unlockAchievement('invalid-id');  // ❌ Type error

Achievement Definition Properties

Each achievement in the array supports the following properties:
id
string
required
Unique identifier for the achievement. Use kebab-case for consistency.
label
string
required
Display name for the achievement. Shown in UI when unlocked (or always if not hidden).
description
string
required
Longer description explaining how to unlock the achievement.
hidden
boolean
default:false
If true, the id, label, and description are hidden until unlocked. Use for secret achievements.
hint
boolean
default:false
If true, only the description is hidden until unlocked. The label is still shown. Use for spoiler-free hints.
maxProgress
number
When provided, this achievement uses progress tracking. It auto-unlocks when progress reaches this value.

Usage Patterns

Basic Achievements

const definitions = defineAchievements([
  {
    id: 'first-login',
    label: 'Welcome!',
    description: 'Log in for the first time',
  },
]);

Progress-Based Achievements

const definitions = defineAchievements([
  {
    id: 'complete-profile',
    label: 'Profile Complete',
    description: 'Fill out all 5 profile fields',
    maxProgress: 5,
  },
]);

Hidden Achievements

const definitions = defineAchievements([
  {
    id: 'secret-code',
    label: 'Code Breaker',
    description: 'Enter the secret code',
    hidden: true, // Everything hidden until unlocked
  },
  {
    id: 'final-boss',
    label: 'Dragon Slayer',
    description: 'Defeat the final boss',
    hint: true, // Label shown, description hidden
  },
]);

Collection Achievements

const definitions = defineAchievements([
  {
    id: 'collect-all-badges',
    label: 'Badge Collector',
    description: 'Collect all badges',
    maxProgress: 10,
  },
]);

// Track with collectItem:
engine.collectItem('collect-all-badges', 'badge-1');
engine.collectItem('collect-all-badges', 'badge-2');

See Also

Build docs developers (and LLMs) love