Skip to content

Commit 8a34789

Browse files
committed
Make Settings type stricter
1 parent 7aadb2a commit 8a34789

2 files changed

Lines changed: 22 additions & 15 deletions

File tree

src/config/index.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -532,14 +532,22 @@ export type SettingDefinition =
532532
type HasDefault = { default: SettingValueType }
533533
type IsRequired = { required: true }
534534

535-
type OptionalSettingKeys<T extends SettingsDefinitionMap> = {
536-
[K in keyof T]: T[K] extends HasDefault | IsRequired ? never : K
535+
type IsOptional = {
536+
default?: never
537+
required?: false
538+
// With just `default` and `required` both optional, the type matches `{}`,
539+
// which means it's a weak type which gets treated differently by TypeScript.
540+
// So we add `description`, which is anyway guaranteed to be present.
541+
description: string
542+
}
543+
544+
type NonOptionalSettingKeys<T extends SettingsDefinitionMap> = {
545+
[K in keyof T]: T[K] extends HasDefault | IsRequired ? K : never
537546
}[keyof T]
538547

539-
type NonOptionalSettingKeys<T extends SettingsDefinitionMap> = Exclude<
540-
keyof T,
541-
OptionalSettingKeys<T>
542-
>
548+
type OptionalSettingKeys<T extends SettingsDefinitionMap> = {
549+
[K in keyof T]: T[K] extends IsOptional ? K : never
550+
}[keyof T]
543551

544552
export type Settings<T extends SettingsDefinitionMap> = {
545553
-readonly [K in OptionalSettingKeys<T>]?: SettingType<T[K]>

test/config.types.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import test from 'ava'
2-
import { SettingsDefinitionMap, SettingDefinition, Settings } from '../src/config'
2+
import { AdapterConfig, SettingDefinition, Settings } from '../src/config'
33

44
// This file has type declarations that test the types of the config system at
55
// compile time.
@@ -158,7 +158,7 @@ const _settingsType: ExpectEqual<
158158
void _settingsType
159159

160160
// Reproduces the bug from `packages/sources/liveart/src/config/index.ts`.
161-
// Annotating the variable with the default `SettingsDefinitionMap` (no
161+
// Annotating the variable with the default `AdapterConfig` (no
162162
// inferred generic) widens the settings map to `Record<string,
163163
// SettingDefinition>`. Any custom setting then resolves via an index
164164
// signature whose value type is the full `SettingType<SettingDefinition>`
@@ -168,20 +168,19 @@ void _settingsType
168168
// distributive over `SettingDefinition`), which silently allowed values
169169
// like `adapterSettings.API_BASE_URL` to be passed into stricter types
170170
// such as Axios's `baseURL: string | undefined`.
171-
const wideConfig: SettingsDefinitionMap = {
171+
const wideConfig: AdapterConfig = new AdapterConfig({
172172
API_BASE_URL: {
173173
type: 'string',
174174
description: 'API base URL',
175175
required: true,
176176
default: 'https://example.com',
177177
},
178-
}
179-
void wideConfig
178+
})
180179

181-
const _wideConfigAccess: ExpectEqual<
182-
Settings<typeof wideConfig>['API_BASE_URL'],
183-
string | number | boolean | undefined
184-
> = true
180+
wideConfig.initialize()
181+
182+
// @ts-expect-error TS2339: Property 'API_BASE_URL' does not exist on type 'AdapterConfig<SettingsDefinitionMap>'.
183+
const _wideConfigAccess = wideConfig.settings.API_BASE_URL
185184
void _wideConfigAccess
186185

187186
// The tests below are not directly a test of the config types, but it

0 commit comments

Comments
 (0)