Skip to content

Commit c38a015

Browse files
Add type-tests to ensure consistent public API expectations (#37)
* expect-type * This is probably a decent start * fix build * Use stricter type check
1 parent 4061983 commit c38a015

File tree

4 files changed

+149
-3
lines changed

4 files changed

+149
-3
lines changed

package.json

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,21 @@
1717
"main": "dist/index.js",
1818
"types": "dist/index.d.ts",
1919
"scripts": {
20-
"build": "tsc && vite build",
20+
"build": "vite build",
2121
"dev": "vite",
2222
"prepare": "npm run build",
23-
"lint": "prettier --check .",
23+
"watch:types": "tsc --noEmit --watch",
24+
"lint": "concurrently 'npm:lint:*(!fix)' --names 'lint:' --prefixColors=auto",
25+
"lint:types": "tsc --noEmit",
26+
"lint:prettier": "prettier --check .",
2427
"lint:fix": "prettier --write .",
2528
"test": "vitest"
2629
},
2730
"devDependencies": {
2831
"@types/node": "^20.11.25",
2932
"@vitest/browser": "^1.5.3",
33+
"concurrently": "^9.0.1",
34+
"expect-type": "^1.0.0",
3035
"prettier": "^3.2.5",
3136
"release-plan": "^0.9.0",
3237
"typescript": "latest",

pnpm-lock.yaml

+45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/public-api-types.ts

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* The purpose of these tests is to make sure the types are exposed how we expect,
3+
* and that we double-check what we're exposing as public API
4+
*/
5+
import {expectTypeOf} from 'expect-type';
6+
import {Signal} from './wrapper.ts';
7+
8+
/**
9+
* Top-Level
10+
*/
11+
expectTypeOf<keyof typeof Signal>().toEqualTypeOf<
12+
'State' | 'Computed' | 'subtle' | 'isState' | 'isComputed' | 'isWatcher'
13+
>();
14+
15+
/**
16+
* Construction works as expected
17+
*/
18+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1);
19+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {});
20+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {equals: (a, b) => true});
21+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {[Signal.subtle.watched]: () => true});
22+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {
23+
[Signal.subtle.unwatched]: () => true,
24+
});
25+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 2);
26+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {equals: (a, b) => true});
27+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {
28+
[Signal.subtle.watched]: () => true,
29+
});
30+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {
31+
[Signal.subtle.unwatched]: () => true,
32+
});
33+
34+
// @ts-expect-error
35+
expectTypeOf<Signal.State<number>>().toBeConstructibleWith();
36+
// @ts-expect-error
37+
expectTypeOf(Signal.State<number>).toBeConstructibleWith('wrong', {});
38+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {
39+
// @ts-expect-error
40+
[Signal.subtle.watched]: 2,
41+
});
42+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {
43+
// @ts-expect-error
44+
[Signal.subtle.unwatched]: 2,
45+
});
46+
expectTypeOf(Signal.State<number>).toBeConstructibleWith(1, {
47+
// @ts-expect-error
48+
typo: (a, b) => true,
49+
});
50+
// @ts-expect-error
51+
expectTypeOf<Signal.Computed<number>>().toBeConstructibleWith();
52+
// @ts-expect-error
53+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith('wrong');
54+
// @ts-expect-error
55+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(2);
56+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {
57+
// @ts-expect-error
58+
[Signal.subtle.watched]: 2,
59+
});
60+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {
61+
// @ts-expect-error
62+
[Signal.subtle.unwatched]: 2,
63+
});
64+
expectTypeOf(Signal.Computed<number>).toBeConstructibleWith(() => 1, {
65+
// @ts-expect-error
66+
typo: (a, b) => true,
67+
});
68+
69+
/**
70+
* Properties on each of the instances / namespaces
71+
*/
72+
expectTypeOf<keyof Signal.State<unknown> & string>().toEqualTypeOf<'get' | 'set'>();
73+
expectTypeOf<keyof Signal.Computed<unknown> & string>().toEqualTypeOf<'get'>();
74+
expectTypeOf<keyof typeof Signal.subtle>().toEqualTypeOf<
75+
| 'untrack'
76+
| 'currentComputed'
77+
| 'introspectSources'
78+
| 'introspectSinks'
79+
| 'hasSinks'
80+
| 'hasSources'
81+
| 'Watcher'
82+
| 'watched'
83+
| 'unwatched'
84+
>();
85+
86+
expectTypeOf<keyof Signal.subtle.Watcher & string>().toEqualTypeOf<
87+
'watch' | 'unwatch' | 'getPending'
88+
>();
89+
90+
/**
91+
* Inference works
92+
*/
93+
expectTypeOf(new Signal.State(0)).toEqualTypeOf<Signal.State<number>>();
94+
expectTypeOf(new Signal.State(0).get()).toEqualTypeOf<number>();
95+
expectTypeOf(new Signal.State(0).set(1)).toEqualTypeOf<void>();

tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"lib": ["DOM", "ES2021"],
1414
"strict": true,
1515
"composite": true,
16-
"forceConsistentCasingInFileNames": true
16+
"forceConsistentCasingInFileNames": true,
17+
"allowImportingTsExtensions": true
1718
},
1819
"exclude": ["**/node_modules/**", "**/*.spec.ts", "**/dist/**/*"],
1920
"include": ["src"]

0 commit comments

Comments
 (0)