From c7aed8d308c629d5e7e23dfa2956a54fbdaf8754 Mon Sep 17 00:00:00 2001 From: Edwin van den Houdt Date: Fri, 4 Sep 2026 15:17:06 +0200 Subject: [PATCH] fix: narrow parseBrpAddress's return type instead of leaking the DTO BrpAddressDto's fields are generated as optional, so returning it directly from parseBrpAddress lost the narrowing the runtime check already did. This broke the build once registratie-lookup.store.ts assigned the parsed address into a stricter local type. Map to a proper BrpAddress domain shape at the trust boundary instead. Co-Authored-By: Claude Sonnet 5 --- .../application/registratie-lookup.store.ts | 2 +- .../registratie/infrastructure/brp.adapter.ts | 33 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/ssp/src/app/registratie/application/registratie-lookup.store.ts b/apps/ssp/src/app/registratie/application/registratie-lookup.store.ts index 3b93480..65abebb 100644 --- a/apps/ssp/src/app/registratie/application/registratie-lookup.store.ts +++ b/apps/ssp/src/app/registratie/application/registratie-lookup.store.ts @@ -41,7 +41,7 @@ export class RegistratieLookupStore { const json = this.adresRes.value(); if (json === undefined) return null; const parsed = parseBrpAddress(json); - return parsed.ok && parsed.value.gevonden && parsed.value.adres ? parsed.value.adres : null; + return parsed.ok && parsed.value.adres ? parsed.value.adres : null; }, ); diff --git a/apps/ssp/src/app/registratie/infrastructure/brp.adapter.ts b/apps/ssp/src/app/registratie/infrastructure/brp.adapter.ts index 512c221..ebae5c0 100644 --- a/apps/ssp/src/app/registratie/infrastructure/brp.adapter.ts +++ b/apps/ssp/src/app/registratie/infrastructure/brp.adapter.ts @@ -3,6 +3,13 @@ import { Result, ok, err } from '@shared/kernel/fp'; import { BrpAddressDto } from '@shared/infrastructure/api-client'; import { ApiClient } from '@shared/infrastructure/api-client'; +/** BRP address lookup, narrowed from the generated (all-optional) `BrpAddressDto` + to what `gevonden` actually guarantees. */ +export interface BrpAddress { + gevonden: boolean; + adres?: { straat: string; postcode: string; woonplaats: string }; +} + /** * Infrastructure adapter for the BRP address lookup, reached only through our own * ("BFF-lite") endpoint — the anti-corruption boundary. Data comes from the .NET @@ -21,20 +28,22 @@ export class BrpAdapter { /** Trust-boundary parse: validate the untrusted response shape. "Geen adres" is a valid outcome (gevonden: false), not a malformed response. ponytail: hand-written; reach for a schema lib once the contract count grows. */ -export function parseBrpAddress(json: unknown): Result { +export function parseBrpAddress(json: unknown): Result { if (typeof json !== 'object' || json === null) return err('brp-address: not an object'); const dto = json as Partial; if (typeof dto.gevonden !== 'boolean') return err('brp-address: missing/invalid gevonden'); - if (dto.gevonden) { - const a = dto.adres; - if ( - !a || - typeof a.straat !== 'string' || - typeof a.postcode !== 'string' || - typeof a.woonplaats !== 'string' - ) { - return err('brp-address: missing/invalid adres'); - } + if (!dto.gevonden) return ok({ gevonden: false }); + const a = dto.adres; + if ( + !a || + typeof a.straat !== 'string' || + typeof a.postcode !== 'string' || + typeof a.woonplaats !== 'string' + ) { + return err('brp-address: missing/invalid adres'); } - return ok({ gevonden: dto.gevonden, adres: dto.adres }); + return ok({ + gevonden: true, + adres: { straat: a.straat, postcode: a.postcode, woonplaats: a.woonplaats }, + }); }