This page is also available in Italiano.

Continua in italiano

Tokens

TinyDI identifies services with tokens, not with strings or classes. A token is created once, and used both to register a service and to resolve it.

Creating a token

ts
interface IMailService {
  send(to: string, body: string): Promise<void>;
}
 
const MailServiceToken = createToken<IMailService>('MailService');

createToken<T>(description) returns a Token<T>. The description string is a human-readable label used only in error messages — it does not need to be unique.

Why a symbol, not a string

Every token wraps a unique JavaScript symbol as its real identity. Two tokens created with the same description are still two distinct registrations:

ts
const a = createToken<string>('Name');
const b = createToken<string>('Name');
 
a.symbol !== b.symbol; // true — distinct tokens, no collision

This rules out an entire category of bugs that string-keyed containers have to work around: two unrelated modules accidentally choosing the same string identifier for different services.

Type inference without generics

The service type T is carried by the token itself, through an optional __type?: T property that exists only at the type level — it is never assigned or read at runtime. Because of it, container.resolve(token) infers the exact return type automatically:

ts
// No explicit generic needed — inferred as IMailService.
const mailService = container.resolve(MailServiceToken);

Type your token with an interface

Always parameterize createToken with an interface (IMailService), not a concrete class. Code that depends on MailServiceToken should never need to import the concrete implementation behind it.

to navigate to select Esc to close