defineConfig(), and TypeScript uses it to infer exact types for every read and write operation — eliminating entire categories of bugs where stored data diverges from what your code expects.
defineConfig(schema)
defineConfig() accepts a plain schema object and returns it unchanged. Its only job is to act as a type anchor so TypeScript can infer the configuration shape throughout your app. Call it once at module level and export the result.
Schema value types
Every field in your schema object must be one of the following value types:| Type | Description |
|---|---|
String | String field |
Number | Number field (must be finite) |
Boolean | Boolean field |
keyring(Type, { id }) | OS keyring-protected field |
optional(Type) | Optional field (may be undefined or null) |
{ ... } | Nested object |
[Type] | Array of a single element type |
[String] or [{ name: String }]. This single-element tuple syntax is how the plugin knows what type to enforce for every item in the array.
Type inference
The plugin exports two utility types that derive TypeScript interfaces directly from your schema:InferUnlocked<S>— The full type with keyring fields as their real value types. Use this when you have access to decrypted data.InferLocked<S>— The type with keyring fields replaced bynull. This is what you receive from.run()after a load or create, before calling.unlock().
keyring(typeCtor, { id })
keyring() marks a field so its value is stored in the OS keychain instead of the config file on disk. At runtime the config file contains a placeholder; the real value is written to and read from the platform keyring.
id must satisfy two rules:
- It must be a non-empty string.
- It must not contain
/, because the plugin uses it as part of the OS keyring user string in the form{account}/{id}.
id must also be unique within the same schema. Reusing an id is a compile-time error enforced by TypeScript’s type system via HasDuplicateKeyringIds, and a runtime error thrown by defineConfig():
optional(schema)
optional() wraps any schema value to indicate the field may be absent from stored data. Validation will not fail when the field is missing, and the inferred TypeScript type includes | undefined.
optional() can wrap any of the following:
- A primitive constructor:
optional(Number) - A keyring field:
optional(keyring(String, { id: "opt-secret" })) - A nested object:
optional({ host: String, port: Number }) - An array:
optional([String])