ripple 0.2.82 → 0.2.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -287,3 +287,7 @@ const methods_returning_arrays = new Set([
287
287
  'toSpliced',
288
288
  'with',
289
289
  ]);
290
+
291
+ export function tracked_array(elements, block) {
292
+ return proxy({ elements, block, from_static: true });
293
+ }
@@ -25,7 +25,7 @@ export function mount(component, options) {
25
25
  if (target.firstChild) {
26
26
  target.textContent = '';
27
27
  }
28
-
28
+
29
29
  target.append(anchor);
30
30
 
31
31
  const cleanup_events = handle_root_events(target);
@@ -42,7 +42,13 @@ export function mount(component, options) {
42
42
 
43
43
  export { create_context as createContext } from './internal/client/context.js';
44
44
 
45
- export { flush_sync as flushSync, track, untrack, deferred } from './internal/client/runtime.js';
45
+ export {
46
+ flush_sync as flushSync,
47
+ track,
48
+ trackSplit,
49
+ untrack,
50
+ deferred,
51
+ } from './internal/client/runtime.js';
46
52
 
47
53
  export { TrackedArray } from './array.js';
48
54
 
@@ -7,14 +7,15 @@ export var TRY_BLOCK = 1 << 6;
7
7
  export var IF_BLOCK = 1 << 7;
8
8
  export var COMPOSITE_BLOCK = 1 << 8;
9
9
  export var ASYNC_BLOCK = 1 << 9;
10
- export var CONTAINS_UPDATE = 1 << 10;
11
- export var CONTAINS_TEARDOWN = 1 << 11;
12
- export var BLOCK_HAS_RUN = 1 << 12;
13
- export var TRACKED = 1 << 13;
14
- export var DERIVED = 1 << 14;
15
- export var DEFERRED = 1 << 15;
16
- export var PAUSED = 1 << 16;
17
- export var DESTROYED = 1 << 17;
10
+ export var HEAD_BLOCK = 1 << 10;
11
+ export var CONTAINS_UPDATE = 1 << 11;
12
+ export var CONTAINS_TEARDOWN = 1 << 12;
13
+ export var BLOCK_HAS_RUN = 1 << 13;
14
+ export var TRACKED = 1 << 14;
15
+ export var DERIVED = 1 << 15;
16
+ export var DEFERRED = 1 << 16;
17
+ export var PAUSED = 1 << 17;
18
+ export var DESTROYED = 1 << 18;
18
19
 
19
20
  export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
20
21
 
@@ -0,0 +1,14 @@
1
+ import { render } from './blocks.js';
2
+ import { HEAD_BLOCK } from './constants.js';
3
+ import { create_text } from './operations.js';
4
+
5
+ /**
6
+ * @param {(anchor: Node) => void} render_fn
7
+ * @returns {void}
8
+ */
9
+ export function head(render_fn) {
10
+ /** @type {Comment | Text} */
11
+ var anchor = document.head.appendChild(create_text());
12
+
13
+ render(() => render_fn(anchor), HEAD_BLOCK);
14
+ }
@@ -1,12 +1,17 @@
1
- export { first_child as child, child_frag, next_sibling as sibling } from './operations.js';
1
+ export {
2
+ first_child as child,
3
+ child_frag,
4
+ next_sibling as sibling,
5
+ document,
6
+ } from './operations.js';
2
7
 
3
8
  export {
4
- set_text,
5
- set_class,
6
- set_attribute,
7
- set_value,
8
- set_checked,
9
- set_selected,
9
+ set_text,
10
+ set_class,
11
+ set_attribute,
12
+ set_value,
13
+ set_checked,
14
+ set_selected,
10
15
  } from './render.js';
11
16
 
12
17
  export { render, render_spread, async, ref } from './blocks.js';
@@ -14,33 +19,33 @@ export { render, render_spread, async, ref } from './blocks.js';
14
19
  export { event, delegate } from './events.js';
15
20
 
16
21
  export {
17
- active_block,
18
- scope,
19
- safe_scope,
20
- with_scope,
21
- get,
22
- get_tracked,
23
- get_derived,
24
- set,
25
- async_computed,
26
- tracked,
27
- spread_props,
28
- computed_property,
29
- call_property,
30
- get_property,
31
- set_property,
32
- update,
33
- update_pre,
34
- update_property,
35
- update_pre_property,
36
- push_component,
37
- pop_component,
38
- untrack,
39
- ref_prop,
40
- fallback,
41
- exclude_from_object,
42
- derived,
43
- maybe_tracked,
22
+ active_block,
23
+ scope,
24
+ safe_scope,
25
+ with_scope,
26
+ get,
27
+ get_tracked,
28
+ get_derived,
29
+ set,
30
+ async_computed,
31
+ tracked,
32
+ spread_props,
33
+ computed_property,
34
+ call_property,
35
+ get_property,
36
+ set_property,
37
+ update,
38
+ update_pre,
39
+ update_property,
40
+ update_pre_property,
41
+ push_component,
42
+ pop_component,
43
+ untrack,
44
+ ref_prop,
45
+ fallback,
46
+ exclude_from_object,
47
+ derived,
48
+ maybe_tracked,
44
49
  } from './runtime.js';
45
50
 
46
51
  export { composite } from './composite.js';
@@ -52,3 +57,7 @@ export { if_block as if } from './if.js';
52
57
  export { try_block as try, aborted } from './try.js';
53
58
 
54
59
  export { template, append } from './template.js';
60
+
61
+ export { tracked_array } from '../../array.js';
62
+
63
+ export { head } from './head.js';
@@ -5,34 +5,38 @@ var first_child_getter;
5
5
  /** @type {() => Node | null} */
6
6
  var next_sibling_getter;
7
7
 
8
+ /** @type {Document} */
9
+ export var document;
10
+
8
11
  export var is_firefox;
9
12
 
10
13
  export function init_operations() {
11
- var node_prototype = Node.prototype;
12
- var element_prototype = Element.prototype;
13
- var object_prototype = Object.prototype;
14
- var event_target_prototype = EventTarget.prototype;
14
+ var node_prototype = Node.prototype;
15
+ var element_prototype = Element.prototype;
16
+ var object_prototype = Object.prototype;
17
+ var event_target_prototype = EventTarget.prototype;
15
18
 
16
- is_firefox = /Firefox/.test(navigator.userAgent);
19
+ is_firefox = /Firefox/.test(navigator.userAgent);
20
+ document = window.document;
17
21
 
18
- // @ts-ignore
19
- first_child_getter = get_descriptor(node_prototype, 'firstChild').get;
20
- // @ts-ignore
21
- next_sibling_getter = get_descriptor(node_prototype, 'nextSibling').get;
22
+ // @ts-ignore
23
+ first_child_getter = get_descriptor(node_prototype, 'firstChild').get;
24
+ // @ts-ignore
25
+ next_sibling_getter = get_descriptor(node_prototype, 'nextSibling').get;
22
26
 
23
- // the following assignments improve perf of lookups on DOM nodes
24
- // @ts-expect-error
25
- element_prototype.__click = undefined;
26
- // @ts-expect-error
27
- element_prototype.__className = '';
28
- // @ts-expect-error
29
- element_prototype.__attributes = null;
30
- // @ts-expect-error
31
- element_prototype.__styles = null;
32
- // @ts-expect-error
33
- element_prototype.__e = undefined;
34
- // @ts-expect-error
35
- event_target_prototype.__root = undefined;
27
+ // the following assignments improve perf of lookups on DOM nodes
28
+ // @ts-expect-error
29
+ element_prototype.__click = undefined;
30
+ // @ts-expect-error
31
+ element_prototype.__className = '';
32
+ // @ts-expect-error
33
+ element_prototype.__attributes = null;
34
+ // @ts-expect-error
35
+ element_prototype.__styles = null;
36
+ // @ts-expect-error
37
+ element_prototype.__e = undefined;
38
+ // @ts-expect-error
39
+ event_target_prototype.__root = undefined;
36
40
  }
37
41
 
38
42
  /**
@@ -42,16 +46,16 @@ export function init_operations() {
42
46
  */
43
47
  /*@__NO_SIDE_EFFECTS__*/
44
48
  export function first_child(node) {
45
- return first_child_getter.call(node);
49
+ return first_child_getter.call(node);
46
50
  }
47
51
 
48
52
  export function child_frag(node) {
49
- var child = first_child(node);
53
+ var child = first_child(node);
50
54
 
51
- if (child.nodeType === 8 && child.data === '') {
52
- return next_sibling(child);
53
- }
54
- return child;
55
+ if (child.nodeType === 8 && child.data === '') {
56
+ return next_sibling(child);
57
+ }
58
+ return child;
55
59
  }
56
60
 
57
61
  /**
@@ -61,9 +65,9 @@ export function child_frag(node) {
61
65
  */
62
66
  /*@__NO_SIDE_EFFECTS__*/
63
67
  export function next_sibling(node) {
64
- return next_sibling_getter.call(node);
68
+ return next_sibling_getter.call(node);
65
69
  }
66
70
 
67
71
  export function create_text(value = '') {
68
- return document.createTextNode(value);
72
+ return document.createTextNode(value);
69
73
  }
@@ -289,36 +289,35 @@ export function derived(fn, block, get, set) {
289
289
 
290
290
  /**
291
291
  * @param {any} v
292
- * @param {TrackOptions<any> | undefined} o
292
+ * @param {Function | undefined} get
293
+ * @param {Function | undefined} set
293
294
  * @param {Block} b
294
- * @returns {Tracked | Derived | Tracked[]}
295
+ * @returns {Tracked | Derived}
295
296
  */
296
- export function track(v, o, b) {
297
- var is_tracked = is_tracked_object(v);
298
- var get;
299
- var set;
300
-
301
- if (o !== undefined) {
302
- get = o.get;
303
- set = o.set;
297
+ export function track(v, get, set, b) {
298
+ if (is_tracked_object(v)) {
299
+ return v;
304
300
  }
305
301
 
306
- if (o === undefined || get || set) {
307
- if (is_tracked) {
308
- return v;
309
- }
310
-
311
- if (typeof v === 'function') {
312
- return derived(v, b, get, set);
313
- }
314
- return tracked(v, b, get, set);
302
+ if (typeof v === 'function') {
303
+ return derived(v, b, get, set);
315
304
  }
305
+ return tracked(v, b, get, set);
306
+ }
307
+
308
+ /**
309
+ * @param {Record<string|symbol, any>} v
310
+ * @param {(symbol | string)[]} l
311
+ * @param {Block} b
312
+ * @returns {Tracked[]}
313
+ */
314
+ export function trackSplit(v, l, b) {
315
+ var is_tracked = is_tracked_object(v);
316
316
 
317
317
  if (is_tracked || typeof v !== 'object' || v === null || is_array(v)) {
318
318
  throw new TypeError('Invalid value: expected a non-tracked object');
319
319
  }
320
320
 
321
- var list = o.split ?? [];
322
321
  /** @type {Tracked[]} */
323
322
  var out = [];
324
323
  /** @type {Record<string|symbol, any>} */
@@ -326,17 +325,23 @@ export function track(v, o, b) {
326
325
  /** @type {Record<PropertyKey, any | null>} */
327
326
  var descriptors = get_descriptors(v);
328
327
 
329
- for (let i = 0, key, t; i < list.length; i++) {
330
- key = list[i];
328
+ for (let i = 0, key, t, exists = true; i < l.length; i++) {
329
+ key = l[i];
331
330
 
332
331
  if (is_tracked_object(v[key])) {
333
332
  t = v[key];
334
333
  } else {
335
- t = define_property(tracked(undefined, b), 'v', descriptors[key]);
334
+ t = tracked(undefined, b);
335
+ exists = !!descriptors[key];
336
+ if (exists) {
337
+ t = define_property(t, 'v', descriptors[key]);
338
+ }
336
339
  }
337
340
 
338
341
  out[i] = t;
339
- descriptors[key] = null;
342
+ if (exists) {
343
+ descriptors[key] = null;
344
+ }
340
345
  }
341
346
 
342
347
  var props = Reflect.ownKeys(descriptors);
@@ -769,7 +774,7 @@ export function get_tracked(tracked) {
769
774
  }
770
775
  var get = tracked.a.get;
771
776
  if (get) {
772
- tracked.v = get(value);
777
+ value = get(value);
773
778
  }
774
779
  return value;
775
780
  }
@@ -785,10 +790,6 @@ export function set(tracked, value, block) {
785
790
  if (value !== old_value) {
786
791
  var tracked_block = tracked.b;
787
792
 
788
- if (!tracked_block) {
789
- debugger;
790
- }
791
-
792
793
  if ((block.f & CONTAINS_TEARDOWN) !== 0) {
793
794
  if (teardown) {
794
795
  old_values.set(tracked, value);
@@ -790,4 +790,5 @@ export {
790
790
  null_instane as null,
791
791
  debugger_builder as debugger,
792
792
  try_builder as try,
793
+ new_builder as new,
793
794
  };
@@ -1,6 +1,7 @@
1
1
  import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { mount, flushSync, effect, track } from 'ripple';
2
+ import { mount, flushSync, effect, track, trackSplit } from 'ripple';
3
3
  import { compile } from 'ripple/compiler';
4
+ import { TRACKED_ARRAY } from '../../src/runtime/internal/client/constants.js';
4
5
 
5
6
  describe('basic client', () => {
6
7
  let container;
@@ -379,8 +380,7 @@ describe('basic client', () => {
379
380
  expect(container.querySelector('.count').textContent).toBe('0');
380
381
  });
381
382
 
382
- // TODO
383
- it.skip('renders multiple reactive lexical blocks with complexity', () => {
383
+ it('renders multiple reactive lexical blocks with complexity', () => {
384
384
 
385
385
  component Basic() {
386
386
  const count = 'count';
@@ -1272,16 +1272,11 @@ describe('basic client', () => {
1272
1272
  expect(container).toMatchSnapshot();
1273
1273
  });
1274
1274
 
1275
- it('can retain reactivity for destructure rest via track split', () => {
1275
+ it('can retain reactivity for destructure rest via track trackSplit', () => {
1276
1276
  let logs = [];
1277
1277
 
1278
1278
  component App() {
1279
- let count = track(0, {
1280
- set(v) {
1281
- logs.push('inside setter');
1282
- return v;
1283
- }
1284
- });
1279
+ let count = track(0);
1285
1280
  let name = track('Click Me');
1286
1281
 
1287
1282
  function buttonRef(el) {
@@ -1294,19 +1289,20 @@ describe('basic client', () => {
1294
1289
  <Child
1295
1290
  class="my-button"
1296
1291
  onClick={() => @name === 'Click Me' ? @name = 'Clicked' : @name = 'Click Me'}
1297
- {count}
1292
+ {@count}
1298
1293
  {ref buttonRef}
1299
- >{@name}</Child>;
1294
+ >{@name}</Child>
1295
+
1296
+ <button onClick={() => @count++}>{'Increment Count'}</button>
1300
1297
  }
1301
1298
 
1302
1299
  component Child(props: PropsWithChildren<{ count: Tracked<number> }>) {
1303
- const [children, count, rest] = track(props, {split: ['children', 'count']});
1300
+ const [children, count, rest] = trackSplit(props, ['children', 'count']);
1304
1301
 
1305
1302
  if (@count < 2) {
1306
1303
  <button {...@rest}><@children /></button>
1307
1304
  }
1308
1305
  <pre>{@count}</pre>
1309
- <button onClick={() => @count++}>{'Increment Count'}</button>
1310
1306
  }
1311
1307
 
1312
1308
  render(App);
@@ -1327,20 +1323,19 @@ describe('basic client', () => {
1327
1323
 
1328
1324
  expect(buttonClickMe.textContent).toBe('Clicked');
1329
1325
  expect(countPre.textContent).toBe('1');
1330
- expect(logs).toEqual(['ref called','inside setter']);
1331
1326
 
1332
1327
  buttonIncrement.click();
1333
1328
  flushSync();
1334
1329
 
1335
- expect(logs).toEqual(['ref called','inside setter','inside setter','cleanup ref']);
1330
+ expect(logs).toEqual(['ref called','cleanup ref']);
1336
1331
  });
1337
1332
 
1338
- it('errors on invalid value as null for track with split', () => {
1333
+ it('errors on invalid value as null for track with trackSplit', () => {
1339
1334
  component App() {
1340
1335
  let message = track('');
1341
1336
 
1342
1337
  try{
1343
- const [a, b, rest] = track(null, { split: ['a', 'b'] });
1338
+ const [a, b, rest] = trackSplit(null, ['a', 'b']);
1344
1339
  } catch(e) {
1345
1340
  @message = e.message;
1346
1341
  }
@@ -1354,12 +1349,12 @@ describe('basic client', () => {
1354
1349
  expect(pre.textContent).toBe('Invalid value: expected a non-tracked object');
1355
1350
  });
1356
1351
 
1357
- it('errors on invalid value as array for track with split', () => {
1352
+ it('errors on invalid value as array for track with trackSplit', () => {
1358
1353
  component App() {
1359
1354
  let message = track('');
1360
1355
 
1361
1356
  try{
1362
- const [a, b, rest] = track([1, 2, 3], { split: ['a', 'b'] });
1357
+ const [a, b, rest] = trackSplit([1, 2, 3], ['a', 'b']);
1363
1358
  } catch(e) {
1364
1359
  @message = e.message;
1365
1360
  }
@@ -1373,13 +1368,13 @@ describe('basic client', () => {
1373
1368
  expect(pre.textContent).toBe('Invalid value: expected a non-tracked object');
1374
1369
  });
1375
1370
 
1376
- it('errors on invalid value as tracked for track with split', () => {
1371
+ it('errors on invalid value as tracked for track with trackSplit', () => {
1377
1372
  component App() {
1378
1373
  const t = track({a: 1, b: 2, c: 3});
1379
1374
  let message = track('');
1380
1375
 
1381
1376
  try{
1382
- const [a, b, rest] = track(t, { split: ['a', 'b'] });
1377
+ const [a, b, rest] = trackSplit(t, ['a', 'b']);
1383
1378
  } catch(e) {
1384
1379
  @message = e.message;
1385
1380
  }
@@ -1393,6 +1388,26 @@ describe('basic client', () => {
1393
1388
  expect(pre.textContent).toBe('Invalid value: expected a non-tracked object');
1394
1389
  });
1395
1390
 
1391
+ it('returns undefined for non-existent props in track with trackSplit', () => {
1392
+ component App() {
1393
+ const [a, b, rest] = trackSplit({a: 1, c: 1}, ['a', 'b']);
1394
+
1395
+ <pre>{@a}</pre>
1396
+ <pre>{String(@b)}</pre>
1397
+ <pre>{@rest.c}</pre>
1398
+ }
1399
+
1400
+ render(App);
1401
+
1402
+ const preA = container.querySelectorAll('pre')[0];
1403
+ const preB = container.querySelectorAll('pre')[1];
1404
+ const preC = container.querySelectorAll('pre')[2];
1405
+
1406
+ expect(preA.textContent).toBe('1');
1407
+ expect(preB.textContent).toBe('undefined');
1408
+ expect(preC.textContent).toBe('1');
1409
+ });
1410
+
1396
1411
  it('returns the same tracked object if plain track is called with a tracked object', () => {
1397
1412
  component App() {
1398
1413
  const t = track({a: 1, b: 2, c: 3});
@@ -1419,4 +1434,97 @@ describe('basic client', () => {
1419
1434
  render(App);
1420
1435
  expect(container).toMatchSnapshot();
1421
1436
  });
1437
+
1438
+ it('uses track get and set where both mutate value', () => {
1439
+ component App() {
1440
+ let count = track(0, v => v + 1, v => v * 2);
1441
+
1442
+
1443
+ <div class='count'>{@count}</div>
1444
+ <button onClick={() => { @count++ }}>{'Increment'}</button>
1445
+ }
1446
+
1447
+ render(App);
1448
+
1449
+ const countDiv = container.querySelector('.count');
1450
+ const button = container.querySelector('button');
1451
+
1452
+ expect(countDiv.textContent).toBe('1');
1453
+
1454
+ button.click();
1455
+ flushSync();
1456
+ expect(countDiv.textContent).toBe('5');
1457
+ });
1458
+
1459
+ it('uses track get and set where set only mutates value', () => {
1460
+ component App() {
1461
+ let count = track(1, v => v, v => v * 2);
1462
+
1463
+
1464
+ <div class='count'>{@count}</div>
1465
+ <button onClick={() => { @count++ }}>{'Increment'}</button>
1466
+ }
1467
+
1468
+ render(App);
1469
+
1470
+ const countDiv = container.querySelector('.count');
1471
+ const button = container.querySelector('button');
1472
+
1473
+ expect(countDiv.textContent).toBe('1');
1474
+
1475
+ button.click();
1476
+ flushSync();
1477
+ expect(countDiv.textContent).toBe('4');
1478
+ });
1479
+
1480
+ it('uses track get and set where get only mutates value', () => {
1481
+ component App() {
1482
+ let count = track(0, v => v + 1, v => v);
1483
+
1484
+
1485
+ <div class='count'>{@count}</div>
1486
+ <button onClick={() => { @count++ }}>{'Increment'}</button>
1487
+ }
1488
+
1489
+ render(App);
1490
+
1491
+ const countDiv = container.querySelector('.count');
1492
+ const button = container.querySelector('button');
1493
+
1494
+ expect(countDiv.textContent).toBe('1');
1495
+
1496
+ button.click();
1497
+ flushSync();
1498
+ expect(countDiv.textContent).toBe('3');
1499
+ });
1500
+
1501
+ it('works as a reactive TrackedArray when constructed using # syntactic sugar', () => {
1502
+ component App() {
1503
+ const array = #[1, 2, 3];
1504
+
1505
+ <pre>{String(array[3])}</pre>
1506
+ <pre>{array[0]}</pre>
1507
+ <pre>{TRACKED_ARRAY in array}</pre>
1508
+
1509
+ <button onClick={() => { array.push(array.length + 1); array[0] = array[0] + 1 }}>{'Add'}</button>
1510
+ }
1511
+
1512
+ render(App);
1513
+
1514
+ const pre1 = container.querySelectorAll('pre')[0];
1515
+ const pre2 = container.querySelectorAll('pre')[1];
1516
+ const pre3 = container.querySelectorAll('pre')[2];
1517
+ const button = container.querySelector('button');
1518
+
1519
+ expect(pre1.textContent).toBe('undefined');
1520
+ expect(pre2.textContent).toBe('1');
1521
+ expect(pre3.textContent).toBe('true');
1522
+
1523
+ button.click();
1524
+ flushSync();
1525
+
1526
+ expect(pre1.textContent).toBe('4');
1527
+ expect(pre2.textContent).toBe('2');
1528
+ });
1422
1529
  });
1530
+
package/types/index.d.ts CHANGED
@@ -76,26 +76,21 @@ export type PropsWithExtras<T extends object> = Props & T & Record<string, unkno
76
76
  export type PropsWithChildren<T extends object = {}> =
77
77
  Expand<Omit<Props, 'children'> & { children: Component } & T>;
78
78
 
79
- type UnwrapTracked<T> = [T] extends [Tracked<infer V>] ? T : Tracked<T>;
80
-
81
- // force ts to evaluate and expand a type fully
82
79
  type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
83
80
 
84
81
  type PickKeys<T, K extends readonly (keyof T)[]> =
85
- { [I in keyof K]: UnwrapTracked<T[K[I] & keyof T]> };
82
+ { [I in keyof K]: Tracked<T[K[I] & keyof T]> };
86
83
 
87
84
  type RestKeys<T, K extends readonly (keyof T)[]> = Expand<Omit<T, K[number]>>;
88
85
 
89
86
  type SplitResult<T extends Props, K extends readonly (keyof T)[]> =
90
- [...PickKeys<T, K>, UnwrapTracked<RestKeys<T, K>>];
91
-
92
- type TrackOptions<T> = { split?: readonly (string | number | symbol)[], get?: (v: T) => T, set?: (v: T) => T };
87
+ [...PickKeys<T, K>, Tracked<RestKeys<T, K>>];
93
88
 
94
- export declare function track<V>(value?: V | (() => V)): Tracked<V>;
89
+ export declare function track<V>(value?: V | (() => V), get?: (v: V) => V, set?: (v: V) => V): Tracked<V>;
95
90
 
96
- export declare function track<V extends Props, const K extends readonly (keyof V)[]>(
97
- value: V,
98
- options: TrackOptions<V>
91
+ export declare function trackSplit<V extends Props, const K extends readonly (keyof V)[]>(
92
+ value: V,
93
+ splitKeys: K,
99
94
  ): SplitResult<V, K>;
100
95
 
101
96
  export function on<Type extends keyof WindowEventMap>(