@@ -87,81 +87,38 @@ export function freezeDraftable<T>(val: T) {
8787 return isDraftable ( val ) ? createNextState ( val , ( ) => { } ) : val
8888}
8989
90- interface WeakMapEmplaceHandler < K extends object , V > {
91- /**
92- * Will be called to get value, if no value is currently in map.
93- */
94- insert ?( key : K , map : WeakMap < K , V > ) : V
95- /**
96- * Will be called to update a value, if one exists already.
97- */
98- update ?( previous : V , key : K , map : WeakMap < K , V > ) : V
99- }
90+ export function getOrInsert < K extends object , V > (
91+ map : WeakMap < K , V > ,
92+ key : K ,
93+ value : V ,
94+ ) : V
95+ export function getOrInsert < K , V > ( map : Map < K , V > , key : K , value : V ) : V
96+ export function getOrInsert < K extends object , V > (
97+ map : Map < K , V > | WeakMap < K , V > ,
98+ key : K ,
99+ value : V ,
100+ ) : V {
101+ if ( map . has ( key ) ) return map . get ( key ) as V
100102
101- interface MapEmplaceHandler < K , V > {
102- /**
103- * Will be called to get value, if no value is currently in map.
104- */
105- insert ?( key : K , map : Map < K , V > ) : V
106- /**
107- * Will be called to update a value, if one exists already.
108- */
109- update ?( previous : V , key : K , map : Map < K , V > ) : V
103+ return map . set ( key , value ) . get ( key ) as V
110104}
111105
112- export function emplace < K , V > (
113- map : Map < K , V > ,
106+ export function getOrInsertComputed < K extends object , V > (
107+ map : WeakMap < K , V > ,
114108 key : K ,
115- handler : MapEmplaceHandler < K , V > ,
109+ compute : ( key : K ) => V ,
116110) : V
117- export function emplace < K extends object , V > (
118- map : WeakMap < K , V > ,
111+ export function getOrInsertComputed < K , V > (
112+ map : Map < K , V > ,
119113 key : K ,
120- handler : WeakMapEmplaceHandler < K , V > ,
114+ compute : ( key : K ) => V ,
121115) : V
122- /**
123- * Allow inserting a new value, or updating an existing one
124- * @throws if called for a key with no current value and no `insert` handler is provided
125- * @returns current value in map (after insertion/updating)
126- * ```ts
127- * // return current value if already in map, otherwise initialise to 0 and return that
128- * const num = emplace(map, key, {
129- * insert: () => 0
130- * })
131- *
132- * // increase current value by one if already in map, otherwise initialise to 0
133- * const num = emplace(map, key, {
134- * update: (n) => n + 1,
135- * insert: () => 0,
136- * })
137- *
138- * // only update if value's already in the map - and increase it by one
139- * if (map.has(key)) {
140- * const num = emplace(map, key, {
141- * update: (n) => n + 1,
142- * })
143- * }
144- * ```
145- *
146- * @remarks
147- * Based on https://github.com/tc39/proposal-upsert currently in Stage 2 - maybe in a few years we'll be able to replace this with direct method calls
148- */
149- export function emplace < K extends object , V > (
150- map : WeakMap < K , V > ,
116+ export function getOrInsertComputed < K extends object , V > (
117+ map : Map < K , V > | WeakMap < K , V > ,
151118 key : K ,
152- handler : WeakMapEmplaceHandler < K , V > ,
119+ compute : ( key : K ) => V ,
153120) : V {
154- if ( map . has ( key ) ) {
155- let value = map . get ( key ) as V
156- if ( handler . update ) {
157- value = handler . update ( value , key , map )
158- map . set ( key , value )
159- }
160- return value
161- }
162- if ( ! handler . insert )
163- throw new Error ( 'No insert provided for key not already in map' )
164- const inserted = handler . insert ( key , map )
165- map . set ( key , inserted )
166- return inserted
121+ if ( map . has ( key ) ) return map . get ( key ) as V
122+
123+ return map . set ( key , compute ( key ) ) . get ( key ) as V
167124}
0 commit comments