Any TypeScript playground or project
Build a typed API layer using Partial for updates, Pick for responses, and Record for config.
1 interface User { 2 id: string; 3 name: string; 4 email: string; 5 password: string; 6 createdAt: Date; 7 role: 'admin' | 'user' | 'guest'; 8 } 9 10 // Derived types — no duplication 11 type CreateUserDto = Omit<User, 'id' | 'createdAt'>; 12 type UpdateUserDto = Partial<Omit<User, 'id' | 'createdAt'>>; 13 type UserPublic = Omit<User, 'password'>; 14 type UserPreview = Pick<User, 'id' | 'name' | 'role'>; 15 16 type RolePermissions = Record<User['role'], string[]>; 17 const permissions: RolePermissions = { 18 admin: ['read', 'write', 'delete', 'manage'], 19 user: ['read', 'write'], 20 guest: ['read'], 21 }; 22 23 // Simulated service 24 class UserService { 25 private users = new Map<string, User>(); 26 27 create(dto: CreateUserDto): UserPublic { 28 const user: User = { ...dto, id: crypto.randomUUID(), createdAt: new Date() }; 29 this.users.set(user.id, user); 30 const { password, ...publicUser } = user; 31 return publicUser; 32 } 33 34 update(id: string, dto: UpdateUserDto): UserPublic | null { 35 const user = this.users.get(id); 36 if (!user) return null; 37 const updated = { ...user, ...dto }; 38 this.users.set(id, updated); 39 const { password, ...publicUser } = updated; 40 return publicUser; 41 } 42 43 list(): UserPreview[] { 44 return Array.from(this.users.values()).map(({ id, name, role }) => ({ id, name, role })); 45 } 46 } 47 48 const svc = new UserService(); 49 const user = svc.create({ name: 'Alice', email: 'alice@x.com', password: 'secret', role: 'user' }); 50 const updated = svc.update(user.id, { name: 'Alice Smith' }); // Only name changes 51 console.log(svc.list());
UserService methods accept correct DTO types; TypeScript rejects wrong shapes
Sign in to share your feedback and join the discussion.