Add election api typescript - #166
Conversation
This commit creates the skeleton application of election-api-javascript in a TypeScript environment.
… files Added Jest configuration for TypeScript support and copied JSON test files from election-api-javascript.
Co-authored-by: Allan Mckinlay <122284042+amckinlaybbc@users.noreply.github.com>
Co-authored-by: Paul Douglas Brimicombe <paul.brimicombe@bbc.co.uk>
Co-authored-by: Paul Douglas Brimicombe <paul.brimicombe@bbc.co.uk>
Co-authored-by: Paul Douglas Brimicombe <paul.brimicombe@bbc.co.uk>
…the store As per comment, I'm returning null to rely on a message that indicates the new data has been created successfully.
Result | null was incompatible with the result type of the function.
Co-authored-by: Paul Douglas Brimicombe <paul.brimicombe@bbc.co.uk>
There was a problem hiding this comment.
copied from slack convo
The TS code looks good, as an MVP could probably get away with just updating the TS/node/dependency versions and verifying the tests still work
Everything i'd probably change to modernise it:
- Node 18 EOL - move to LTS
- TS 5.1.3 - move to 7.0.2 (probably restricting candidates if we stay on 5)
- Express/other deps need updating
- Replace jest with vitest (nightmare to work with TS)
- replace ts-node/ts-node-dev with tsx
- convert from commonJS to ESM
- Update readme instructions to install latest stuff
- Update any links referencing old js files
Co-authored-by: Luke Taylor <37551503+iuketaylor@users.noreply.github.com>
iuketaylor
left a comment
There was a problem hiding this comment.
Mostly looks really good 🙌
I think we'll need to change the validation logic and also add some config options to the tsconfig though
| function validateResult(resultCandidate: any): boolean { | ||
| if (typeof resultCandidate !== "object" || resultCandidate === null) | ||
| return false; | ||
| const { id, candidate, votes } = resultCandidate; | ||
| return ( | ||
| typeof id === "number" && | ||
| typeof candidate === "string" && | ||
| typeof votes === "number" && | ||
| id != null | ||
| ); | ||
| } |
There was a problem hiding this comment.
I don't think this validation is correct, just a couple of things:
- We should be asserting on
id,name,seqNo, andpartyResultsrather thancandidate, andvotes - To do it the "TypeScript way" you'd want to use a type predicate eg
(...): value is Result(see examples below), this will make sure the type is narrowed and correct at runtime - A weird JS/TS quirk:
typeof resultCandidate !== "object"- this isn't enough unfortunately because JS is strange it also thinks null and Arrays can be typeof "object" so to be "correct" we'd need to handle those more explicitly eg:
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
What I think the validation would look like if we wanted to match the Java version:
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function validatePartyResult(value: unknown): value is PartyResult {
if (!isRecord(value)) return false;
return (
typeof value.party === "string" &&
typeof value.votes === "number" &&
typeof value.share === "number"
);
}
function validateResult(value: unknown): value is Result {
if (!isRecord(value)) return false;
return (
typeof value.id === "number" &&
typeof value.name === "string" &&
typeof value.seqNo === "number" &&
Array.isArray(value.partyResults) &&
value.partyResults.every(validatePartyResult)
);
}
| "module": "es6", | ||
|
|
||
| /* Emit */ | ||
| "outDir": "./dist", |
There was a problem hiding this comment.
We'll need to add "rootDir" here cos TypeScript 7 requires it when we implement the comment below
| "outDir": "./dist", | |
| "outDir": "./dist", | |
| "rootDir": "./src" |
|
|
||
| /* Completeness */ | ||
| "skipLibCheck": true | ||
| } |
There was a problem hiding this comment.
We'll need to restrict what TypeScript builds, currently everything is being build which means Vitest is discovering both the source and the built files and running the tests twice resulting in the tests duplicated.
Before:
✓ dist/test/scoreboard.spec.js (4 tests) 894ms
✓ first 554 331ms
✓ test all results 460ms
✓ test/scoreboard.spec.ts (4 tests) 898ms
✓ first 554 330ms
✓ test all results 463ms
Test Files 2 passed (2)
Tests 8 passed (8)
Start at 11:16:09
Duration 1.18s (transform 75ms, setup 0ms, import 361ms, tests 1.79s, environment 0ms)
After:
✓ test/scoreboard.spec.ts (4 tests) 943ms
✓ Scoreboard Tests (4)
✓ first 5 24ms
✓ first 100 77ms
✓ first 554 364ms
✓ test all results 475ms
Test Files 1 passed (1)
Tests 4 passed (4)
Start at 11:17:09
Duration 1.16s (transform 28ms, setup 0ms, import 117ms, tests 943ms, environment 0ms)
| } | |
| }, | |
| "include": ["src/**/*.ts"], | |
| "exclude": ["dist", "node_modules"] | |
| "private": true, | ||
| "devDependencies": { | ||
| "@types/express": "5.0.6", | ||
| "@types/node": "26.2.0", |
There was a problem hiding this comment.
Minor one but probably makes sense to align the Node types with the Node version 24 we're using
What?
This is restoring the typescript port of the election api test that Rossano did. With some tweaks to freshen it.
Why?
We're appearing a bit dated when we give users pure JS tests. In some cases, we specifically want to assess their typescript abilities, and this hasn't been possible with these standard tests.