feat(types): introduce SessionId/ProjectId branded types (SOLID Phase 3)
This commit is contained in:
parent
7ba63db101
commit
f2a7d385d6
2 changed files with 70 additions and 0 deletions
52
v2/src/lib/types/ids.test.ts
Normal file
52
v2/src/lib/types/ids.test.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { SessionId, ProjectId, type SessionId as SessionIdType, type ProjectId as ProjectIdType } from './ids';
|
||||
|
||||
describe('branded types', () => {
|
||||
describe('SessionId', () => {
|
||||
it('creates a SessionId from a string', () => {
|
||||
const id = SessionId('sess-abc-123');
|
||||
expect(id).toBe('sess-abc-123');
|
||||
});
|
||||
|
||||
it('is usable as a string (template literal)', () => {
|
||||
const id = SessionId('sess-1');
|
||||
expect(`session: ${id}`).toBe('session: sess-1');
|
||||
});
|
||||
|
||||
it('is usable as a Map key', () => {
|
||||
const map = new Map<SessionIdType, number>();
|
||||
const id = SessionId('sess-1');
|
||||
map.set(id, 42);
|
||||
expect(map.get(id)).toBe(42);
|
||||
});
|
||||
|
||||
it('equality works between two SessionIds with same value', () => {
|
||||
const a = SessionId('sess-1');
|
||||
const b = SessionId('sess-1');
|
||||
expect(a === b).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ProjectId', () => {
|
||||
it('creates a ProjectId from a string', () => {
|
||||
const id = ProjectId('proj-xyz');
|
||||
expect(id).toBe('proj-xyz');
|
||||
});
|
||||
|
||||
it('is usable as a Map key', () => {
|
||||
const map = new Map<ProjectIdType, string>();
|
||||
const id = ProjectId('proj-1');
|
||||
map.set(id, 'test-project');
|
||||
expect(map.get(id)).toBe('test-project');
|
||||
});
|
||||
});
|
||||
|
||||
describe('type safety (compile-time)', () => {
|
||||
it('both types are strings at runtime', () => {
|
||||
const sid = SessionId('s1');
|
||||
const pid = ProjectId('p1');
|
||||
expect(typeof sid).toBe('string');
|
||||
expect(typeof pid).toBe('string');
|
||||
});
|
||||
});
|
||||
});
|
||||
18
v2/src/lib/types/ids.ts
Normal file
18
v2/src/lib/types/ids.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Branded types for domain identifiers — prevents accidental swapping of sessionId/projectId
|
||||
// These are compile-time only; at runtime they are plain strings.
|
||||
|
||||
/** Unique identifier for an agent session */
|
||||
export type SessionId = string & { readonly __brand: 'SessionId' };
|
||||
|
||||
/** Unique identifier for a project */
|
||||
export type ProjectId = string & { readonly __brand: 'ProjectId' };
|
||||
|
||||
/** Create a SessionId from a raw string */
|
||||
export function SessionId(value: string): SessionId {
|
||||
return value as SessionId;
|
||||
}
|
||||
|
||||
/** Create a ProjectId from a raw string */
|
||||
export function ProjectId(value: string): ProjectId {
|
||||
return value as ProjectId;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue