export type ToKeyFunction < K > = ( key : K ) => string ; export type Predicate < V > = ( value : V ) => boolean ; /**
 * A dict that is sparse but we can still have empty values.
 */ export class SparseDict < K , V > { private backing : { [ key ] : V ; } = { } ; constructor ( private readonly toKey , private readonly newValue ) { } public read ( key ) { return this . backing [ key ] || undefined ; } public get ( key ) { const k = this . toKey ( key ) ; if ( ! this . backing [ k ] ) { this . backing [ k ] = this . newValue ( key ) ; } return this . backing [ k ] ; } /**
     * Purge items from the set that match the predicate
     */ public purge ( predicate ) { for ( const key of this . keys ( ) ) { const value = this . backing [ key ] ; if ( value && predicate ( value ) ) { delete this . backing [ key ] ; } } } /**
     * Get with the raw key, no conversion.
     */ public getWithKey ( k ) { return this . backing [ k ] || undefined ; } public keys ( ) { return Object . keys ( this . backing ) ; } public values ( ) { return Object . values ( this . backing ) ; } public delete ( key ) { delete this . backing [ key ] ; } }