From 65e8bf61f62e9da7fe9dc78980f7379b39e73a59 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Wed, 19 Aug 2026 09:54:32 +0200 Subject: [PATCH 1/2] test: add tsd type tests for SemVerVersion/SemVerRange assignability closes #73 Adds src/versions.test-d.ts, following the existing .test-d.ts pattern (hex.test-d.ts, json.test-d.ts, caip-types.test-d.ts), proving the two opaque SemVer types are not mutually assignable at the type level even though both are strings at runtime, and that a plain string literal isn't assignable to either without going through its assertion function first. --- src/versions.test-d.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/versions.test-d.ts diff --git a/src/versions.test-d.ts b/src/versions.test-d.ts new file mode 100644 index 00000000..d30ed0e8 --- /dev/null +++ b/src/versions.test-d.ts @@ -0,0 +1,27 @@ +import { expectAssignable, expectNotAssignable } from 'tsd'; + +import type { SemVerRange, SemVerVersion } from '.'; +import { assertIsSemVerRange, assertIsSemVerVersion } from '.'; + +// A value produced via a type's own assertion function is assignable to +// itself: + +const unsafeVersion = '1.0.0'; +assertIsSemVerVersion(unsafeVersion); +expectAssignable(unsafeVersion); + +const unsafeRange = '^1.0.0'; +assertIsSemVerRange(unsafeRange); +expectAssignable(unsafeRange); + +// SemVerVersion and SemVerRange are distinct opaque types, and are not +// mutually assignable, even though both are strings at runtime: + +expectNotAssignable(unsafeVersion); +expectNotAssignable(unsafeRange); + +// A plain string is not assignable to either opaque type without going +// through the type's own validation/assertion function: + +expectNotAssignable('1.0.0'); +expectNotAssignable('^1.0.0'); From d6f39a98710aefa6536299efca64b9c1d248c660 Mon Sep 17 00:00:00 2001 From: gomes <17035424+gomesalexandre@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:10:06 +0200 Subject: [PATCH 2/2] fix: point test:types at the src test-d files directly yarn test:types (tsd) has been a silent no-op repo-wide since the package.json types field became ./dist/index.d.cts. tsd 0.29's auto-discovery does typingsFile.replace(/\.d\.ts$/, '.test-d.ts'), which doesn't match .d.cts, so the configured tsd.directory: "src" fallback never fires - instead globby matches the literal ./dist/index.d.cts path (which exists once CI builds before running test:types), finds one file with zero assertions in it, and tsd reports a clean pass on nothing. Reproduced: appending a bogus assertion to any existing *.test-d.ts file still exits 0 under the old script. Fixed by pointing tsd at the src glob explicitly, matching the tsd.directory config's original intent. Verified against all 5 existing test-d files (hex, json, caip-types, misc, versions): clean pass with the fix, and the same bogus-assertion mutation now correctly fails. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 15028861..8608bead 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "prepack": "./scripts/prepack.sh", "test": "yarn test:source && yarn test:types", "test:source": "jest && jest-it-up", - "test:types": "tsd", + "test:types": "tsd --files 'src/**/*.test-d.ts'", "test:watch": "jest --watch" }, "resolutions": {