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