11import assert from 'node:assert' ;
22import { cloneDeep , get , merge , set , defaults as setDefaults } from 'lodash-es' ;
33import sortKeys from 'sort-keys' ;
4+ import type { Get } from 'type-fest' ;
45import type { MemFsEditor } from 'mem-fs-editor' ;
5- import type { StorageRecord , StorageValue } from '../types.js' ;
6+ import type { StorageValue } from '../types.js' ;
67
78/**
89 * Proxy handler for Storage
@@ -71,7 +72,7 @@ export type StorageOptions = {
7172 * }
7273 * }
7374 */
74- class Storage {
75+ class Storage < StorageRecord extends Record < string , any > = Record < string , any > > {
7576 path : string ;
7677 name ?: string ;
7778 fs : MemFsEditor ;
@@ -196,7 +197,7 @@ class Storage {
196197 if ( this . lodashPath ) {
197198 set ( fullStore , this . name , value ) ;
198199 } else {
199- fullStore [ this . name ] = value ;
200+ ( fullStore as any ) [ this . name ] = value ;
200201 }
201202 } else {
202203 fullStore = value ;
@@ -217,17 +218,17 @@ class Storage {
217218 * @param key The key under which the value is stored.
218219 * @return The stored value. Any JSON valid type could be returned
219220 */
220- get < T extends StorageValue = StorageValue > ( key : string ) : T {
221- return this . _store [ key ] as T ;
221+ get < const Key extends keyof StorageRecord > ( key : Key ) : StorageRecord [ Key ] {
222+ return this . _store [ key ] ;
222223 }
223224
224225 /**
225226 * Get a stored value from a lodash path
226227 * @param path The path under which the value is stored.
227228 * @return The stored value. Any JSON valid type could be returned
228229 */
229- getPath < T extends StorageValue = StorageValue > ( path : string ) : T {
230- return get ( this . _store , path ) as T ;
230+ getPath < const KeyPath extends string > ( path : KeyPath ) : Get < StorageValue , KeyPath > {
231+ return get ( this . _store , path ) ;
231232 }
232233
233234 /**
@@ -244,21 +245,26 @@ class Storage {
244245 * @param val Any valid JSON type value (String, Number, Array, Object).
245246 * @return val Whatever was passed in as val.
246247 */
247- set < V = StorageValue > ( value : V ) : V ;
248- set < V = StorageValue > ( key : string | number , value ?: V ) : V | undefined ;
249- set < V = StorageValue > ( key : string | number | V , value ?: V ) : V | undefined {
248+ set ( value : Partial < StorageRecord > ) : StorageRecord ;
249+ set < const Key extends keyof StorageRecord , const Value extends StorageRecord [ Key ] > (
250+ key : Key ,
251+ value ?: Value ,
252+ ) : Value | undefined ;
253+ set ( key : string | number | Partial < StorageRecord > , value ?: StorageValue ) : StorageRecord | StorageValue | undefined {
250254 const store = this . _store ;
255+ let ret : StorageValue | StorageValue | undefined ;
251256
252257 if ( typeof key === 'object' ) {
253- value = Object . assign ( store , key ) ;
258+ ret = Object . assign ( store , key ) ;
254259 } else if ( typeof key === 'string' || typeof key === 'number' ) {
255- store [ key ] = value as any ;
260+ ( store as any ) [ key ] = value ;
261+ ret = value ;
256262 } else {
257263 throw new TypeError ( `key not supported ${ typeof key } ` ) ;
258264 }
259265
260266 this . _persist ( store ) ;
261- return value ;
267+ return ret ;
262268 }
263269
264270 /**
@@ -267,7 +273,7 @@ class Storage {
267273 * @param val Any valid JSON type value (String, Number, Array, Object).
268274 * @return val Whatever was passed in as val.
269275 */
270- setPath ( path : string | number , value : StorageValue ) {
276+ setPath < const KeyPath extends string > ( path : KeyPath , value : Get < StorageValue , KeyPath > ) : Get < StorageValue , KeyPath > {
271277 assert ( typeof value !== 'function' , "Storage value can't be a function" ) ;
272278
273279 const store = this . _store ;
@@ -280,7 +286,7 @@ class Storage {
280286 * Delete a key from the store and schedule a save.
281287 * @param key The key under which the value is stored.
282288 */
283- delete ( key : string ) {
289+ delete ( key : keyof StorageRecord ) : void {
284290 const store = this . _store ;
285291
286292 delete store [ key ] ;
@@ -293,7 +299,7 @@ class Storage {
293299 * @param defaults Key-value object to store.
294300 * @return val Returns the merged options.
295301 */
296- defaults ( defaults : StorageRecord ) : StorageRecord {
302+ defaults ( defaults : Partial < StorageRecord > ) : StorageRecord {
297303 assert ( typeof defaults === 'object' , 'Storage `defaults` method only accept objects' ) ;
298304 const store = setDefaults ( { } , this . _store , defaults ) ;
299305 this . _persist ( store ) ;
@@ -304,7 +310,7 @@ class Storage {
304310 * @param defaults Key-value object to store.
305311 * @return val Returns the merged object.
306312 */
307- merge ( source : StorageRecord ) {
313+ merge ( source : Partial < StorageRecord > ) : StorageRecord {
308314 assert ( typeof source === 'object' , 'Storage `merge` method only accept objects' ) ;
309315 const value = merge ( { } , this . _store , source ) ;
310316 this . _persist ( value ) ;
@@ -317,9 +323,9 @@ class Storage {
317323 * Some paths need to be escaped. Eg: ["dotted.path"]
318324 * @return Returns a new Storage.
319325 */
320- createStorage ( path : string ) : Storage {
326+ createStorage < const KeyPath extends string > ( path : KeyPath ) : Storage < Get < StorageRecord , KeyPath > > {
321327 const childName = this . name ? `${ this . name } .${ path } ` : path ;
322- return new Storage ( childName , this . fs , this . path , { lodashPath : true } ) ;
328+ return new Storage < Get < StorageRecord , KeyPath > > ( childName , this . fs , this . path , { lodashPath : true } ) ;
323329 }
324330
325331 /**
0 commit comments