Skip to content

Commit 20d894c

Browse files
authored
Add type system tests for SettingsDefinition (#747)
1 parent 371dd8f commit 20d894c

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

test/config.types.test.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { SettingDefinition, Settings } from '../src/config'
2+
3+
// This file has type declarations that test the types of the config system at
4+
// compile time.
5+
6+
// Declarations with a (@)ts-expect-error comment are expected to produce a
7+
// type error, and compilation will fail if they don't.
8+
9+
// Declarations are followed by `void foo` to prevent "declared but never used"
10+
// errors from the TypeScript compiler.
11+
12+
// Utility types:
13+
14+
// This uses a trick proposed on https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
15+
type Equal<A, B> =
16+
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false
17+
18+
// Without this, the type system sometimes doesn't realize that two types are
19+
// equal even though they are.
20+
type Expand<T> = { [K in keyof T]: T[K] }
21+
22+
type ExpectEqual<A, E> =
23+
Equal<Expand<A>, Expand<E>> extends true
24+
? true
25+
: { error: 'Types are not equal'; actual: A; expected: E }
26+
27+
// Test that the shape of the SettingsDefinition is enforced by the type
28+
// system.
29+
30+
// @ts-expect-error test
31+
const _assertStringDefault: SettingDefinition = {
32+
type: 'string',
33+
description: 'string settings cannot have a number as default',
34+
default: 2,
35+
}
36+
void _assertStringDefault
37+
38+
// @ts-expect-error test
39+
const _assertNumberDefault: SettingDefinition = {
40+
type: 'string',
41+
description: 'number settings cannot have a boolean as default',
42+
default: true,
43+
}
44+
void _assertNumberDefault
45+
46+
// @ts-expect-error test
47+
const _assertBooleanDefault: SettingDefinition = {
48+
type: 'boolean',
49+
description: 'boolean settings cannot have a string as default',
50+
default: 'true',
51+
}
52+
void _assertBooleanDefault
53+
54+
// @ts-expect-error test
55+
const _assertEnumNumberDefault: SettingDefinition = {
56+
type: 'enum',
57+
description: 'enum settings cannot have a number as default',
58+
options: ['option1', 'option2', 'option3'],
59+
default: 1,
60+
}
61+
void _assertEnumNumberDefault
62+
63+
// Ideally this would fail but it doesn't
64+
const _assertEnumOptionDefault: SettingDefinition = {
65+
type: 'enum',
66+
description: 'enum settings can have a default that is not a valid option',
67+
options: ['option1', 'option2', 'option3'],
68+
default: 'option4',
69+
}
70+
void _assertEnumOptionDefault
71+
72+
// Test that the type of the settings is correctly inferred from the type of
73+
// the settings definition.
74+
75+
const testSettingsDefinition = {
76+
optionalStringSetting: {
77+
type: 'string',
78+
description: 'optional string setting',
79+
},
80+
requiredStringSetting: {
81+
type: 'string',
82+
description: 'required string setting',
83+
required: true,
84+
},
85+
defaultStringSetting: {
86+
type: 'string',
87+
description: 'string setting with default value',
88+
default: 'default value',
89+
},
90+
optionalNumberSetting: {
91+
type: 'number',
92+
description: 'optional number setting',
93+
},
94+
requiredNumberSetting: {
95+
type: 'number',
96+
description: 'required number setting',
97+
required: true,
98+
},
99+
defaultNumberSetting: {
100+
type: 'number',
101+
description: 'number setting with default value',
102+
default: 42,
103+
},
104+
optionalBooleanSetting: {
105+
type: 'boolean',
106+
description: 'optional boolean setting',
107+
},
108+
requiredBooleanSetting: {
109+
type: 'boolean',
110+
description: 'required boolean setting',
111+
required: true,
112+
},
113+
defaultBooleanSetting: {
114+
type: 'boolean',
115+
description: 'boolean setting with default value',
116+
default: true,
117+
},
118+
optionalEnumSetting: {
119+
type: 'enum',
120+
description: 'optional enum setting',
121+
options: ['option1', 'option2', 'option3'],
122+
},
123+
requiredEnumSetting: {
124+
type: 'enum',
125+
description: 'required enum setting',
126+
required: true,
127+
options: ['option1', 'option2', 'option3'],
128+
},
129+
defaultEnumSetting: {
130+
type: 'enum',
131+
description: 'enum setting with default value',
132+
options: ['option1', 'option2', 'option3'],
133+
default: 'option1',
134+
},
135+
} as const
136+
void testSettingsDefinition
137+
138+
type ExpectedSettingsType = {
139+
optionalStringSetting?: string
140+
requiredStringSetting: string
141+
defaultStringSetting: string
142+
optionalNumberSetting?: number
143+
requiredNumberSetting: number
144+
defaultNumberSetting: number
145+
optionalBooleanSetting?: boolean
146+
requiredBooleanSetting: boolean
147+
defaultBooleanSetting: boolean
148+
optionalEnumSetting?: 'option1' | 'option2' | 'option3'
149+
requiredEnumSetting: 'option1' | 'option2' | 'option3'
150+
defaultEnumSetting: 'option1' | 'option2' | 'option3'
151+
}
152+
153+
const _settingsType: ExpectEqual<
154+
Settings<typeof testSettingsDefinition>,
155+
ExpectedSettingsType
156+
> = true
157+
void _settingsType

0 commit comments

Comments
 (0)