Skip to content

Commit

Permalink
Add time(clock) shorthand
Browse files Browse the repository at this point in the history
  • Loading branch information
zerobias committed Dec 15, 2023
1 parent de23027 commit c60611a
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 17 deletions.
22 changes: 15 additions & 7 deletions src/time/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
import { createEffect, Unit, restore, sample, Store } from 'effector';
import { createEffect, Unit, restore, sample, Store, is } from 'effector';

const defaultNow = <Time = number>() => Date.now() as unknown as Time;

type NoInfer<T> = [T][T extends any ? 0 : never];

export function time<Time = number>({
clock,
getNow,
initial,
}: {
export function time(clock: Unit<any>): Store<number>;
export function time<Time = number>(config: {
clock: Unit<any>;
getNow?: () => Time;
initial?: NoInfer<Time>;
}): Store<Time> {
}): Store<Time>;
export function time<Time = number>(
args:
| {
clock: Unit<any>;
getNow?: () => Time;
initial?: NoInfer<Time>;
}
| Unit<any>,
): Store<Time> {
const argsShape = is.unit(args) ? { clock: args } : args;
const { clock, getNow, initial } = argsShape;
const timeReader = getNow ?? defaultNow;
const readNowFx = createEffect<void, Time>(timeReader);
const $time = restore(readNowFx, initial ?? timeReader());
Expand Down
65 changes: 59 additions & 6 deletions src/time/readme.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,71 @@
# time

```ts
import { time } from 'patronum';
// or
import { time } from 'patronum/time';
```

## `time(clock)`

:::note since
patronum 1.7.0
patronum 2.1.0
Use `time({ clock })` with patronum < 2.1.0
:::

### Motivation

The method allow to read current time and write it to store

### Formulae

```ts
$time = time(clock);
```

- Initialize `$time` with `Date.now()`
- When `clock` is triggered, call `Date.now()` to update `$time` with results

### Arguments

1. `clock: Event<any> | Effect<any, any, any> | Store<any>` — The unit triggers time reading and updates `$time` store

`Time` is a generic type argument used for overriding time reader function. By default, is is `number`

### Returns

`$time: Store<Time>` — Store contains unix timestamp snapshot, updates when `clock` triggers.
Initialized with `Date.now()`

### Example

```ts
import { time } from 'patronum';
// or
import { time } from 'patronum/time';

const tick = createEvent();
const $time = time(tick);

$time.watch((time) => console.log('time', time));
// => time 1660293358847

tick();
// => time 1660293358848
await new Promise((res) => setTimeout(res, 100));
tick();
// => 1660293358952
```

[Try it](https://share.effector.dev/ZKcm1ebv)

## `time({clock, getNow, initial})`

:::note since
patronum 1.7.0
:::

### Motivation

The method allow to read current time just as an effector method.
The method allow to read current time and write it to store. Object form allows to use additional parameters: `getNow` and `initial`

### Formulae

Expand All @@ -26,8 +79,8 @@ $time = time({ clock, getNow, initial });
### Arguments

1. `clock: Event<any> | Effect<any, any, any> | Store<any>` — The unit triggers time reading and updates `$time` store
2. `getNow?: () => Time` — A custom function to read time when `clock` triggers. **Must be synchronous**.
3. `initial?: Time` — Initial state for `$time` store. If not passed `getNow` is called.
2. `getNow: () => Time` Optional. A custom function to read time when `clock` triggers. **Must be synchronous**.
3. `initial: Time` Optional. Initial state for `$time` store. If not passed `getNow` is called.

`Time` is a generic type argument used for overriding time reader function. By default, is is `number`

Expand Down
4 changes: 2 additions & 2 deletions src/time/time.fork.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ test('store must correctly serializes', async () => {
await allSettled(clock, { scope: scopeB });
expect(serialize(scopeA)).toMatchInlineSnapshot(`
{
"-9m03zk|-xu6mk0": 2,
"-9m03zk|-k3vl4d": 2,
}
`);
expect(serialize(scopeB)).toMatchInlineSnapshot(`
{
"-9m03zk|-xu6mk0": 3,
"-9m03zk|-k3vl4d": 3,
}
`);
});
17 changes: 17 additions & 0 deletions src/time/time.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ test('initialize store with the current time', () => {
expect(is.store($time)).toBeTruthy();
expect($time.getState()).toBe(TIME_0);
});
test('initialize store with the current time (shorthand)', () => {
const $time = time(createEvent());
expect(is.store($time)).toBeTruthy();
expect($time.getState()).toBe(TIME_0);
});

test('update store on each clock trigger', () => {
const clock = createEvent();
Expand All @@ -31,6 +36,18 @@ test('update store on each clock trigger', () => {
jest.setSystemTime(TIME_2);
expect($time.getState()).toBe(TIME_1);
});
test('update store on each clock trigger (shorthand)', () => {
const clock = createEvent();
const $time = time(clock);
expect($time.getState()).toBe(TIME_0);

jest.setSystemTime(TIME_1);
clock();
expect($time.getState()).toBe(TIME_1);

jest.setSystemTime(TIME_2);
expect($time.getState()).toBe(TIME_1);
});

test('update store only after clock', async () => {
const clock = createEvent();
Expand Down
10 changes: 8 additions & 2 deletions test-typings/time.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { expectType } from 'tsd';
import { Store, createStore, createEvent, createEffect, createDomain } from 'effector';
import { Store, createStore, createEvent, createEffect } from 'effector';
import { time } from '../dist/time';

// Returns correct default Store value
{
const clock = createEvent<void>();

expectType<Store<number>>(time({ clock }));
expectType<Store<number>>(time(clock));
expectType<Store<number>>(time({ clock, initial: 100 }));
}

Expand Down Expand Up @@ -65,9 +66,14 @@ import { time } from '../dist/time';
expectType<Store<number>>(time({ clock: effectFx }));
expectType<Store<number>>(time({ clock: $store }));

expectType<Store<number>>(time(event));
expectType<Store<number>>(time(effectFx));
expectType<Store<number>>(time($store));

const fn = () => null;
const domain = createDomain()

// @ts-expect-error
time({ clock: fn });
// @ts-expect-error
time(fn);
}

0 comments on commit c60611a

Please sign in to comment.