From cba36394c902b3366305f7acffe47127124af3c0 Mon Sep 17 00:00:00 2001 From: Julien Gautier Date: Tue, 26 May 2026 13:36:41 +0200 Subject: [PATCH] fix(structures): widen via String() in narrowing test to satisfy lint (#231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary One-line lint fix in [apps/portal-bff/src/structures/structure-kind.spec.ts](apps/portal-bff/src/structures/structure-kind.spec.ts) — the narrowing test failed CI lint with `@typescript-eslint/no-inferrable-types` on `const candidate: string = 'medico_social'`. The naive fix (drop the annotation) would make the test vacuous: TypeScript would infer the literal type `'medico_social'`, which is already a `StructureKind` subtype, so the runtime guard `isStructureKind` would have nothing to prove. Fix instead: widen via `String('medico_social')` — the inferred return type is `string`, the narrowing check stays meaningful, the linter is happy. ## What lands | File | Change | | --- | --- | | `apps/portal-bff/src/structures/structure-kind.spec.ts` | `const candidate: string = 'medico_social'` → `const candidate = String('medico_social')`. 3-line comment explains why `String()` rather than dropping the annotation. | ## Test plan - [x] `pnpm exec nx lint portal-bff` — `0 errors, 13 warnings` (warnings all pre-existing in unrelated files). - [x] `pnpm exec prettier --check` clean. - [ ] **CI** — `pnpm ci:check` passes on this PR. - [ ] **Review focus** — the comment block explaining the round-trip rationale (otherwise the `String('literal')` pattern reads like over-engineering). ## Notes for the reviewer - **Pre-existing warnings are NOT addressed here.** The 13 remaining lint warnings (non-null assertions in `principal-extractor.spec.ts`, unused underscored params in `rate-limit.middleware.ts`, one stale eslint-disable in `downstream-token-cache.service.spec.ts`) are outside the scope of this PR — none of them block CI today, and folding them in would muddle the diff. Worth a separate `chore(bff): sweep lint warnings` PR if/when those become noisy. - **Why `String()` over an `as string` cast?** Both would work, but `String()` is a real runtime operation (returns a fresh `string`) — `as string` is type-system-only. The runtime call has a tiny side-effect (and the inferred return type really IS `string`, not the literal), so the narrowing test stays semantically real. - **No new error class.** The lint rule `@typescript-eslint/no-inferrable-types` is set to `error` severity in the workspace config; my narrowing test was just the first case to trip it. --------- Co-authored-by: Julien Gautier Reviewed-on: https://git.unespace.com/julien/apf_portal/pulls/231 --- apps/portal-bff/src/structures/structure-kind.spec.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/portal-bff/src/structures/structure-kind.spec.ts b/apps/portal-bff/src/structures/structure-kind.spec.ts index 55e21e9..6745e42 100644 --- a/apps/portal-bff/src/structures/structure-kind.spec.ts +++ b/apps/portal-bff/src/structures/structure-kind.spec.ts @@ -35,7 +35,10 @@ describe('isStructureKind', () => { }); it('narrows the type at the call site', () => { - const candidate: string = 'medico_social'; + // Round-trip through `String()` to widen the literal to `string`. + // Without this the inferred type is `'medico_social'`, already a + // StructureKind subtype — the narrowing check would be vacuous. + const candidate = String('medico_social'); if (!isStructureKind(candidate)) { throw new Error('unreachable — candidate is a known kind'); }