From 69c797cd3856fb2bd0d3d6916ba2adb633793db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dafydd=20Ll=C5=B7r=20Pearson?= Date: Wed, 25 Oct 2023 18:04:47 +0100 Subject: [PATCH] chore: More type tightening (#173) ## What does this PR do? - Follow on from https://github.com/theopensystemslab/planx-core/pull/78 - Removes all `implicitAny`s apart from those in `src/export/digitalPlanning/model.ts` ### Next steps - Write `Passport.get()` method to replace the placeholder `Passport.generic()` (see https://github.com/theopensystemslab/planx-core/pull/78#discussion_r1363887300) - Test TS compilation on Pizza - Rebase / merge / cherry-pick https://github.com/theopensystemslab/planx-core/pull/68 to move things forward there --- jest.config.ts | 2 +- package.json | 2 +- src/export/bops/index.ts | 27 +++++++++++++++++----- src/export/bops/tests/addressInput.test.ts | 12 ++++++---- src/export/bops/tests/contactInput.test.ts | 12 ++++++---- tsconfig.build.json | 21 +++++++++++++++++ tsconfig.json | 1 - 7 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 tsconfig.build.json diff --git a/jest.config.ts b/jest.config.ts index e4a899e7..e6f84d61 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -9,7 +9,7 @@ export default { }, ], }, - testPathIgnorePatterns: ["dist/*", "tests/*"], + testPathIgnorePatterns: ["dist/*"], collectCoverage: true, coverageReporters: ["html", "lcov", "text-summary"], coverageDirectory: "./coverage", diff --git a/package.json b/package.json index 0b0916eb..68a7647f 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "types": "./dist/index.d.ts", "scripts": { - "build": "rimraf ./types ./dist && tsc --project ./tsconfig.types.json && tsc && pnpm copy-json-schema", + "build": "rimraf ./types ./dist && tsc --project ./tsconfig.types.json && tsc --project ./tsconfig.build.json && pnpm copy-json-schema", "examples": "rimraf ./examples && ts-node ./src/templates/generateExamples.ts", "lint": "eslint 'src/**/*.{js,ts}' && prettier -c src/**/*", "lint:fix": "eslint --fix 'src/**/*.{js,ts}' && prettier -w src/**/*", diff --git a/src/export/bops/index.ts b/src/export/bops/index.ts index 47bfc9c0..e2b3fae5 100644 --- a/src/export/bops/index.ts +++ b/src/export/bops/index.ts @@ -18,6 +18,7 @@ import type { Response, ResponseMetaData, SiteAddress, + Value, } from "../../types"; import { BOPSFullPayload, @@ -27,6 +28,7 @@ import { GOV_PAY_PASSPORT_KEY, USER_ROLES, } from "../../types"; +import { DataObject } from "./../../types/data"; const bopsDictionary = { // applicant or agent details can be provided via TextInput(plural) or ContactInput component @@ -90,6 +92,10 @@ function exhaustiveCheck(type: never): never { throw new Error(`Unhandled type ${type}`); } +function isDataObject(value: Value): value is DataObject { + return typeof value === "object" && value !== null; +} + export function formatProposalDetails({ flow, breadcrumbs, @@ -153,6 +159,13 @@ export function formatProposalDetails({ try { const addressObject = Object.values(crumb.data!)[0]; + if (!addressObject) + throw Error("Missing AddressInput component type"); + if (!isDataObject(addressObject)) + throw Error( + "Invalid addressObject produced by AddressInput component", + ); + // `Object.values(addressObject)` won't guarantee key order, so explicitly create a new array const orderedAddressKeys = [ "line1", @@ -162,10 +175,10 @@ export function formatProposalDetails({ "postcode", "country", ]; - const orderedAddressItems: string[] = []; + const orderedAddressItems: Array = []; orderedAddressKeys.forEach((key) => { - if (addressObject?.[key]) { - orderedAddressItems.push(addressObject?.[key]); + if (addressObject[key]) { + orderedAddressItems.push(addressObject[key]); } }); return [orderedAddressItems.filter(Boolean).join(", ")]; @@ -360,9 +373,11 @@ export function computeBOPSParams({ ]) as Array; const constraints: BOPSFullPayload["constraints"] = {}; passportConstraints.forEach((response: EnhancedGISResponse) => { - Object.entries(response.constraints).forEach(([key, constraint]) => { - constraints[key] = constraint.value; - }); + Object.entries(response.constraints || []).forEach( + ([key, constraint]) => { + constraints[key] = constraint.value; + }, + ); }); data.constraints = constraints; diff --git a/src/export/bops/tests/addressInput.test.ts b/src/export/bops/tests/addressInput.test.ts index cf072679..26b70270 100644 --- a/src/export/bops/tests/addressInput.test.ts +++ b/src/export/bops/tests/addressInput.test.ts @@ -54,8 +54,10 @@ describe("AddressInput details are set correctly based on the breadcrumbs", () = (detail) => detail.question === "What's your address", )?.[0]; - expect(addressInputItem?.responses[0]?.["value"]).toEqual( - "10 Main Street, Apt 1, Southwark, London, SE5 0HU, UK", + expect(addressInputItem?.responses[0]).toEqual( + expect.objectContaining({ + value: "10 Main Street, Apt 1, Southwark, London, SE5 0HU, UK", + }), ); }); @@ -84,8 +86,10 @@ describe("AddressInput details are set correctly based on the breadcrumbs", () = (detail) => detail.question === "What's your address", )?.[0]; - expect(addressInputItem?.responses[0]?.["value"]).toEqual( - "10 Main Street, Southwark, SE5 0HU", + expect(addressInputItem?.responses[0]).toEqual( + expect.objectContaining({ + value: "10 Main Street, Southwark, SE5 0HU", + }), ); }); }); diff --git a/src/export/bops/tests/contactInput.test.ts b/src/export/bops/tests/contactInput.test.ts index 6c47f3bd..01e86469 100644 --- a/src/export/bops/tests/contactInput.test.ts +++ b/src/export/bops/tests/contactInput.test.ts @@ -70,8 +70,10 @@ describe("ContactInput details are set correctly based on the breadcrumbs", () = (detail) => detail.question === "Your contact details", )?.[0]; - expect(contactInputItem?.responses[0]?.["value"]).toEqual( - "Ms Jane Doe Open Systems Lab 0123456789 test@test.com", + expect(contactInputItem?.responses[0]).toEqual( + expect.objectContaining({ + value: "Ms Jane Doe Open Systems Lab 0123456789 test@test.com", + }), ); }); @@ -104,8 +106,10 @@ describe("ContactInput details are set correctly based on the breadcrumbs", () = (detail) => detail.question === "Your contact details", )?.[0]; - expect(contactInputItem?.responses[0]?.["value"]).toEqual( - "Jane Doe 0123456789 test@test.com", + expect(contactInputItem?.responses[0]).toEqual( + expect.objectContaining({ + value: "Jane Doe 0123456789 test@test.com", + }), ); }); }); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..328933ef --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "allowJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "lib": ["DOM", "ESNext"], + "target": "es2022", + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": false, + "resolveJsonModule": true, + "skipLibCheck": true, + "jsx": "react", + "strict": true, + "rootDir": "./src", + "declaration": true, + "outDir": "dist" + }, + "include": ["./src/*", "./src/**/*"], + "exclude": ["./src/**/*.test.ts", "./src/**/mocks"] +} diff --git a/tsconfig.json b/tsconfig.json index 328933ef..dc3db328 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,5 +17,4 @@ "outDir": "dist" }, "include": ["./src/*", "./src/**/*"], - "exclude": ["./src/**/*.test.ts", "./src/**/mocks"] }