Skip to content

Commit d68f9e2

Browse files
committed
BREAKING_CHANGE: modify typings linked with parent view models access
1 parent 1274570 commit d68f9e2

File tree

5 files changed

+84
-47
lines changed

5 files changed

+84
-47
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919

2020
export class ViewModelImpl<
2121
Payload extends AnyObject = EmptyObject,
22-
ParentViewModel extends ViewModel<any> = ViewModel<any>,
22+
ParentViewModel extends ViewModel<any> | null = null,
2323
>
2424
extends AbstractViewModel<Payload, ParentViewModel>
2525
implements ViewModel<Payload, ParentViewModel>
Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { describe, expect, it, vi } from 'vitest';
22

3+
import { AnyObject, EmptyObject, Maybe } from '../utils/types';
4+
35
import { AbstractViewModelStore } from './abstract-view-model.store';
46
import { TestViewModelImpl } from './abstract-view-model.test';
57
import { AbstractViewModelParams } from './abstract-view-model.types';
8+
import { ViewModel } from './view-model';
9+
import { ViewModelStore } from './view-model.store';
610
import {
711
ViewModelCreateConfig,
812
ViewModelGenerateIdConfig,
913
} from './view-model.store.types';
1014

11-
export class TestViewModelStoreImpl extends AbstractViewModelStore<TestViewModelImpl> {
15+
export class TestViewModelStoreImpl extends AbstractViewModelStore {
1216
spies = {
1317
generateViewModelId: vi.fn(),
1418
};
1519

16-
createViewModel<VM extends TestViewModelImpl>(
17-
config: ViewModelCreateConfig<VM>,
18-
): VM {
20+
createViewModel<VM extends ViewModel>(config: ViewModelCreateConfig<VM>): VM {
1921
const VM = config.VM;
2022

2123
const params: AbstractViewModelParams<VM['payload']> = {
@@ -27,7 +29,7 @@ export class TestViewModelStoreImpl extends AbstractViewModelStore<TestViewModel
2729
return new VM(params);
2830
}
2931

30-
generateViewModelId<VM extends TestViewModelImpl>(
32+
generateViewModelId<VM extends ViewModel>(
3133
config: ViewModelGenerateIdConfig<VM>,
3234
): string {
3335
const result = super.generateViewModelId(config);
@@ -36,30 +38,64 @@ export class TestViewModelStoreImpl extends AbstractViewModelStore<TestViewModel
3638
}
3739
}
3840

39-
const createTestViewModelStore = () => {
40-
return new TestViewModelStoreImpl();
41-
};
42-
4341
describe('AbstractViewModelStore', () => {
4442
it('create instance', () => {
45-
const vmStore = createTestViewModelStore();
43+
const vmStore = new TestViewModelStoreImpl();
4644
expect(vmStore).toBeDefined();
4745
});
4846

4947
it('is able to attach view model', async () => {
50-
const vmStore = createTestViewModelStore();
51-
const vm = new TestViewModelImpl({ id: '1', payload: '1' });
48+
const vmStore = new TestViewModelStoreImpl();
49+
const vm = new TestViewModelImpl({ id: '1' });
5250
await vmStore.attach(vm);
5351
expect(vmStore.get('1')).toBe(vm);
5452
expect(vmStore.instanceAttachedCount.get('1')).toBe(1);
5553
});
5654

5755
it('is able to detach view model', async () => {
58-
const vmStore = createTestViewModelStore();
59-
const vm = new TestViewModelImpl({ id: '1', payload: '1' });
56+
const vmStore = new TestViewModelStoreImpl();
57+
const vm = new TestViewModelImpl({ id: '1' });
6058
await vmStore.attach(vm);
6159
await vmStore.detach('1');
6260
expect(vmStore.get('1')).toBe(null);
6361
expect(vmStore.instanceAttachedCount.get('1')).toBe(undefined);
6462
});
63+
64+
it('accessing to parent view models using store', async () => {
65+
class TestViewModelImpl1<
66+
Payload extends AnyObject = EmptyObject,
67+
ParentViewModel extends ViewModel<any> | null = null,
68+
> extends TestViewModelImpl<Payload, ParentViewModel> {
69+
constructor(
70+
private vmStore: ViewModelStore,
71+
params?: Partial<AbstractViewModelParams<Payload>>,
72+
) {
73+
super(params);
74+
}
75+
76+
protected getParentViewModel(
77+
parentViewModelId: Maybe<string>,
78+
): ParentViewModel {
79+
return this.vmStore.get(parentViewModelId)! as ParentViewModel;
80+
}
81+
}
82+
83+
class VMParent extends TestViewModelImpl1 {}
84+
class VMChild extends TestViewModelImpl1<any, VMParent> {}
85+
86+
const vmStore = new TestViewModelStoreImpl();
87+
88+
const parentVM = new VMParent(vmStore, { id: 'parent' });
89+
90+
await vmStore.attach(parentVM);
91+
92+
const childVM = new VMChild(vmStore, {
93+
id: 'child',
94+
parentViewModelId: 'parent',
95+
});
96+
97+
await vmStore.attach(parentVM);
98+
99+
expect(childVM.parentViewModel.id).toBe('parent');
100+
});
65101
});

src/view-model/abstract-view-model.test.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { describe, expect, it, vi } from 'vitest';
22

3-
import { Maybe } from '../utils/types';
3+
import { AnyObject, EmptyObject, Maybe } from '../utils/types';
44

55
import { AbstractViewModel } from './abstract-view-model';
6+
import { AbstractViewModelParams } from './abstract-view-model.types';
67
import { ViewModel } from './view-model';
78

8-
export class TestViewModelImpl extends AbstractViewModel<any, any> {
9+
export class TestViewModelImpl<
10+
Payload extends AnyObject = EmptyObject,
11+
ParentViewModel extends ViewModel<any> | null = null,
12+
> extends AbstractViewModel<Payload, ParentViewModel> {
913
spies = {
1014
mount: vi.fn(),
1115
unmount: vi.fn(),
@@ -14,10 +18,18 @@ export class TestViewModelImpl extends AbstractViewModel<any, any> {
1418
didUnmount: vi.fn(),
1519
};
1620

21+
constructor(params?: Partial<AbstractViewModelParams<Payload>>) {
22+
super({
23+
...params,
24+
id: params?.id ?? '1',
25+
payload: params?.payload ?? ({} as any),
26+
});
27+
}
28+
1729
protected getParentViewModel(
1830
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1931
parentViewModelId: Maybe<string>,
20-
): ViewModel<any, ViewModel<any, any>> | null {
32+
): ParentViewModel {
2133
throw new Error('Method not implemented.');
2234
}
2335

@@ -43,94 +55,83 @@ export class TestViewModelImpl extends AbstractViewModel<any, any> {
4355
this.spies.didUnmount();
4456
}
4557
}
46-
export const createTestViewModel = ({
47-
id = '1',
48-
payload = {},
49-
}: {
50-
id?: string;
51-
payload?: any;
52-
} = {}) => {
53-
const vm = new TestViewModelImpl({ id, payload });
54-
55-
return vm;
56-
};
5758

5859
describe('AbstractViewModel', () => {
5960
it('create instance', () => {
60-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
61+
const vm = new TestViewModelImpl();
6162
expect(vm).toBeDefined();
6263
});
6364

6465
it('has id', () => {
65-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
66+
const vm = new TestViewModelImpl();
6667
expect(vm.id).toBe('1');
6768
});
6869

6970
it('has payload', () => {
70-
const vm = new TestViewModelImpl({ id: '1', payload: { test: 1 } });
71+
const vm = new TestViewModelImpl({ payload: { test: 1 } });
7172
expect(vm.payload).toEqual({ test: 1 });
7273
});
7374

7475
it('has isMounted', () => {
75-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
76+
const vm = new TestViewModelImpl();
7677
expect(vm.isMounted).toBe(false);
7778
});
7879

7980
it('has mount method', () => {
80-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
81+
const vm = new TestViewModelImpl();
8182
expect(vm.mount).toBeDefined();
8283
});
8384

8485
it('has unmount method', () => {
85-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
86+
const vm = new TestViewModelImpl();
8687
expect(vm.unmount).toBeDefined();
8788
});
8889

8990
it('has dispose', () => {
90-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
91+
const vm = new TestViewModelImpl();
9192
expect(vm.dispose).toBeDefined();
9293
});
9394

9495
it('mount should be called once', () => {
95-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
96+
const vm = new TestViewModelImpl();
9697

9798
vm.mount();
9899

99100
expect(vm.spies.mount).toHaveBeenCalledOnce();
100101
});
101102

102103
it('didMount should be called after mount', () => {
103-
const vm = new TestViewModelImpl({ id: '1', payload: {} });
104+
const vm = new TestViewModelImpl();
104105

105106
vm.mount();
106107

107108
expect(vm.spies.didMount).toHaveBeenCalledOnce();
108109
});
109110

110111
it('isMounted should be true after mount', () => {
111-
const vm = createTestViewModel();
112+
const vm = new TestViewModelImpl();
112113
vm.mount();
113114
expect(vm.isMounted).toBe(true);
114115
});
115116

116117
it('unmount should be called once', () => {
117-
const vm = createTestViewModel();
118+
const vm = new TestViewModelImpl();
118119

119120
vm.unmount();
120121

121122
expect(vm.spies.unmount).toHaveBeenCalledOnce();
122123
});
123124

124125
it('didUnmount should be called after unmount', () => {
125-
const vm = createTestViewModel();
126+
const vm = new TestViewModelImpl();
126127

127128
vm.unmount();
128129

129130
expect(vm.spies.didUnmount).toHaveBeenCalledOnce();
130131
});
131132

132133
it('isMounted should be false after unmount', () => {
133-
const vm = createTestViewModel();
134+
const vm = new TestViewModelImpl();
134135
vm.mount();
135136
vm.unmount();
136137
expect(vm.isMounted).toBe(false);

src/view-model/abstract-view-model.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { ViewModel } from './view-model';
1010

1111
export abstract class AbstractViewModel<
1212
Payload extends AnyObject = EmptyObject,
13-
ParentViewModel extends ViewModel<any> = ViewModel<any>,
14-
> implements ViewModel<Payload>
13+
ParentViewModel extends ViewModel<any> | null = null,
14+
> implements ViewModel<Payload, ParentViewModel>
1515
{
1616
private abortController: AbortController;
1717

@@ -114,7 +114,7 @@ export abstract class AbstractViewModel<
114114
*/
115115
protected abstract getParentViewModel(
116116
parentViewModelId: Maybe<string>,
117-
): ParentViewModel | null;
117+
): ParentViewModel;
118118

119119
/**
120120
* @deprecated use {didUnmount} instead

src/view-model/view-model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { AbstractViewModel } from './abstract-view-model';
88
*/
99
export interface ViewModel<
1010
Payload extends AnyObject = EmptyObject,
11-
ParentViewModel extends ViewModel<any> = ViewModel<any, any>,
11+
ParentViewModel extends ViewModel<any> | null = null,
1212
> {
1313
/**
1414
* The unique identifier for the view model.
@@ -33,7 +33,7 @@ export interface ViewModel<
3333
* Parent view model is the one that is above the current view model in the tree of view models.
3434
* Parent view model is determined by the getParentViewModel() method.
3535
*/
36-
readonly parentViewModel: ParentViewModel | null;
36+
readonly parentViewModel: ParentViewModel;
3737

3838
/**
3939
* The method that is called when the view model is mounted.

0 commit comments

Comments
 (0)