API with phantom
- TypeScript course
- Advanced
- Lesson 23/57
- 4 min
Learn safe API design with phantom types.
API design with phantoms
Phantom types prevent API functions from being called in the wrong order or with wrong arguments. For example, an HTTP request type can carry the authentication state as a phantom argument; thus send accepts only requests in the Authenticated state.
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;
function authenticate(r: Anonymous): Authenticated {
return r;
}
function send(r: Authenticated): string {
return r.url;
}Compile-time safety
In a phantom-designed API, misuse becomes a compile error; for example, send cannot be called with an Anonymous request. This prevents runtime errors and makes the code safe.
const req: Anonymous = { url: "/api" };
const authed = authenticate(req);
send(authed); // valid
send(req); // error: Anonymous is not AuthenticatedPractice Authentication flow with phantoms
Define the Request<Auth> generic type (body url: string). Create Anonymous and Authenticated types with phantom arguments. Write authenticate(r: Anonymous): Authenticated and send(r: Authenticated): string functions. Start from an Anonymous value, authenticate it, get the URL via send, and print it via console.log.
Starter code
// Request<Auth> generic türünü tanımla (Auth gövdede kullanılmasın)
// Anonymous ve Authenticated türlerini phantom argümanlarla oluştur
// authenticate ve send fonksiyonlarını yaz
// Anonymous değerinden başla, authenticate ve send uygula, sonucu yazdırSample solution
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;
function authenticate(r: Anonymous): Authenticated {
return r;
}
function send(r: Authenticated): string {
return r.url;
}
const req: Anonymous = { url: "/api" };
const url = send(authenticate(req));
console.log(url);Expected output
/api
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is the goal of safe API design with phantoms?
- Hiding API calls
- Ensuring API functions are called only in the correct order and state Correct answer
- Writing shorter function signatures
- Parameter validation at runtime
Explanation: With phantoms each API function accepts only values in a specific state; thus wrong order or missing steps become compile errors.
2 Which type does send accept
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;
function send(r: ____): string { return r.url; }
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;
function send(r: Authenticated): string { return r.url; }
Explanation: send accepts only Authenticated requests; this prevents sending an unauthenticated request at compile time.
3 Phantom API parts
| Term | Meaning |
|---|---|
Anonymous durumu |
not yet authenticated |
Authenticated durumu |
ready for send |
send(r: Authenticated) |
accepts only verified request |
Phantom Auth parametresi |
carries auth state |