Skip to content

Commit b7c6da4

Browse files
committed
Implement requested changes from review
1 parent dc96469 commit b7c6da4

File tree

10 files changed

+64
-36
lines changed

10 files changed

+64
-36
lines changed

src/Collection.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,22 @@ class Collection<ItemType extends ResourceInterface, ResourceType extends Collec
4141
/**
4242
* Returns a promise that resolves to the collection object, once all items have been loaded
4343
*/
44-
private _itemLoader (array: Array<ItemType>) : Promise<this> {
44+
private _itemLoader (array: Array<ItemType | Link>) : Promise<this> {
4545
if (!this._containsUnknownEntityReference(array)) {
46-
return Promise.resolve(this) // we know that this object must be of type CollectionInterface
46+
return Promise.resolve(this)
4747
}
4848

4949
// eager loading of 'fetchAllUri' (e.g. parent for embedded collections)
5050
if (this.config.avoidNPlusOneRequests) {
51-
return this.apiActions.reload<ItemType>(this) as unknown as Promise<this> // we know that reload resolves to a type CollectionInterface
51+
return this.apiActions.reload<this>(this)
5252

5353
// no eager loading: replace each reference (Link) with a Resource (ResourceInterface)
5454
} else {
5555
const arrayWithReplacedReferences = this._replaceEntityReferences(array)
5656

5757
return Promise.all(
5858
arrayWithReplacedReferences.map(entry => entry._meta.load)
59-
).then(() => this) // we know that this object must be of type CollectionInterface
59+
).then(() => this)
6060
}
6161
}
6262

@@ -65,12 +65,10 @@ class Collection<ItemType extends ResourceInterface, ResourceType extends Collec
6565
* (or from the API if necessary), and returns that as a new array. In case some of the entity references in
6666
* the array have not finished loading yet, returns a LoadingCollection instead.
6767
* @param array possibly mixed array of values and references
68-
* @param fetchAllUri URI that allows fetching all array items in a single network request, if known
69-
* @param fetchAllProperty property in the entity from fetchAllUri that will contain the array
7068
* @returns array the new array with replaced items, or a LoadingCollection if any of the array
7169
* elements is still loading.
7270
*/
73-
private _mapArrayOfEntityReferences (array: Array<ItemType>): Array<ItemType> {
71+
private _mapArrayOfEntityReferences (array: Array<Link>): Array<ItemType> {
7472
if (!this._containsUnknownEntityReference(array)) {
7573
return this._replaceEntityReferences(array)
7674
}
@@ -90,15 +88,15 @@ class Collection<ItemType extends ResourceInterface, ResourceType extends Collec
9088
/**
9189
* Replace each item in array with a proper Resource (or LoadingResource)
9290
*/
93-
private _replaceEntityReferences (array: Array<ItemType>): Array<ItemType> {
94-
const links = array.filter(entry => isEntityReference(entry)) as unknown as Link[]
91+
private _replaceEntityReferences (array: Array<ItemType | Link>): Array<ItemType> {
92+
const links = array.filter(isEntityReference)
9593
return links.map(entry => this.apiActions.get<ItemType>(entry.href) as ItemType)
9694
}
9795

9896
/**
9997
* Returns true if any of the items within 'array' is not yet known to the API (meaning it has never been loaded)
10098
*/
101-
private _containsUnknownEntityReference (array: Array<ItemType>): boolean {
99+
private _containsUnknownEntityReference (array: Array<ItemType | Link>): array is Array<Link> {
102100
return array.some(entry => isEntityReference(entry) && this.apiActions.isUnknown(entry.href))
103101
}
104102
}

src/LoadingCollection.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ class LoadingCollection {
1010
* @param loadArray Promise that resolves once the array has finished loading
1111
* @param existingContent optionally set the elements that are already known, for random access
1212
*/
13-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
1413
static create<ItemType extends ResourceInterface> (loadArray: Promise<Array<ItemType> | undefined>, existingContent: Array<ItemType> = []): Array<ItemType> {
1514
// if the Promise resolves to undefined, provide empty array
1615
// this could happen if items is accessed from a LoadingResource, which resolves to a normal entity without 'items'

src/ResourceCreator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ApiActions } from './interfaces/Interfaces'
22
import type { InternalConfig } from './interfaces/Config'
3-
import type { StoreData, StoreDataCollection, StoreDataEntity } from './interfaces/StoreData'
3+
import type { StoreData } from './interfaces/StoreData'
44
import type ResourceInterface from './interfaces/ResourceInterface'
55
import Resource from './Resource'
66
import Collection from './Collection'
@@ -60,11 +60,11 @@ class ResourceCreator<RootEndpoint extends ResourceInterface = ResourceInterface
6060
wrapData<ResourceType extends ResourceInterface<ResourceType>> (data: StoreData<ResourceType>): ResourceType {
6161
// Store data looks like a collection --> return CollectionInterface
6262
if (isCollection<ResourceType>(data)) {
63-
return new Collection<ResourceType>(data as StoreDataCollection<ResourceType>, this.apiActions, this, this.config) as unknown as ResourceType// these parameters are passed to Resource constructor
63+
return new Collection<ResourceType>(data, this.apiActions, this, this.config) as unknown as ResourceType
6464

6565
// else Store Data looks like an entity --> return normal Resource
6666
} else {
67-
return new Resource<ResourceType>(data as StoreDataEntity<ResourceType>, this.apiActions, this, this.config) as unknown as ResourceType
67+
return new Resource<ResourceType>(data, this.apiActions, this, this.config) as unknown as ResourceType
6868
}
6969
}
7070
}

src/halHelpers.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type keyValueObject = Record<string, unknown>
77
/**
88
* Verifies that two arrays contain the same values while ignoring the order
99
*/
10-
function isEqualIgnoringOrder<T> (array: Array<T>, other: Array<T>) :boolean {
10+
function isEqualIgnoringOrder<T> (array: Array<T>, other: Array<T>): boolean {
1111
return array.length === other.length && array.every(elem => other.includes(elem))
1212
}
1313

@@ -27,10 +27,9 @@ function isTemplatedLink (object: keyValueObject): object is TemplatedLink {
2727
* @param object to be examined
2828
* @returns boolean true if the object looks like an entity reference, false otherwise
2929
*/
30-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31-
function isEntityReference (object: any): object is Link {
30+
function isEntityReference (object: unknown): object is Link {
3231
if (!object) return false
33-
return isEqualIgnoringOrder(Object.keys(object), ['href'])
32+
return isEqualIgnoringOrder(Object.keys((object as Link)), ['href'])
3433
}
3534

3635
/**
@@ -58,12 +57,10 @@ function isVirtualResource (resource: ResourceInterface): resource is VirtualRes
5857
* @param object to be examined
5958
* @returns boolean true if the object looks like a standalone collection, false otherwise
6059
*/
61-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
62-
function isCollection<StoreType> (object: any): object is StoreDataCollection<StoreType> {
63-
return !!(object && Array.isArray(object.items))
60+
function isCollection<StoreType> (object: unknown): object is StoreDataCollection<StoreType> {
61+
return !!(object && Array.isArray((object as StoreDataCollection<StoreType>).items))
6462
}
6563

66-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6764
function isCollectionInterface<Item extends ResourceInterface> (object: ResourceInterface): object is CollectionInterface<Item> {
6865
return isCollection(object._storeData)
6966
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import type { CollectionInterface } from './interfaces/CollectionInterface'
22
import type { ResourceInterface } from './interfaces/ResourceInterface'
3+
import type { ResourceReference, CollectionReference } from './interfaces/References'
34
import type { HalJsonVuex } from './interfaces/Interfaces'
45
import HalJsonVuexPlugin from './HalJsonVuexPlugin'
56
import Resource from './Resource'
67
import Collection from './Collection'
78
import LoadingResource from './LoadingResource'
89

910
export type { ResourceInterface, CollectionInterface, HalJsonVuex }
11+
export type { ResourceReference, CollectionReference }
1012

1113
export { HalJsonVuexPlugin, Resource, Collection, LoadingResource }
1214

src/interfaces/CollectionInterface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type ResourceInterface from './ResourceInterface'
22

3+
/**
4+
* Generic interface for a collection ResourceInterface (e.g. a HAl resource with an own store entry and a self link)
5+
*/
36
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47
export interface CollectionInterface<ItemType extends ResourceInterface, ResourceType extends CollectionInterface<ItemType, ResourceType> = any> extends ResourceInterface<ResourceType> {
58
items: Array<ItemType>

src/interfaces/Interfaces.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import type { ResourceInterface } from './ResourceInterface'
22

3+
/**
4+
* This interface defines the API actions that can be performed with the HalJsonVuex plugin.
5+
*/
36
export interface ApiActions<RootEndpoint extends ResourceInterface = ResourceInterface> {
47
get:<ResourceType extends ResourceInterface = RootEndpoint> (uriOrEntity?: string | ResourceInterface) => ResourceType
58
reload:<ResourceType extends ResourceInterface = RootEndpoint> (uriOrEntity: string | ResourceInterface) => Promise<ResourceType>
@@ -10,9 +13,15 @@ export interface ApiActions<RootEndpoint extends ResourceInterface = ResourceInt
1013
isUnknown: (uri: string) => boolean
1114
}
1215

16+
/**
17+
* These methods only modify the Vuex store. They do not interact with the API.
18+
*/
1319
export interface StoreActions {
1420
purge<Item extends ResourceInterface> (uriOrEntity: string | Item): void
1521
purgeAll (): void
1622
}
1723

24+
/**
25+
* This is the main interface for the HalJsonVuex plugin. It combines the API actions and the store actions.
26+
*/
1827
export type HalJsonVuex<RootEndpoint extends ResourceInterface = ResourceInterface> = ApiActions<RootEndpoint> & StoreActions

src/interfaces/References.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ResourceInterface } from './ResourceInterface'
2+
import { CollectionInterface } from './CollectionInterface'
3+
4+
/**
5+
* Reference to a resource. This is used to create properties in a ResourceInterface that point to other resources.
6+
* @param T The type of the resource.
7+
* @param Params Parameters that can be passed to the request, e.g. to modify the resource request.
8+
*/
9+
export type ResourceReference<T extends ResourceInterface<T>, Params = undefined> = Params extends undefined
10+
? () => T
11+
: (arg: Params) => T;
12+
13+
/**
14+
* Reference to a collection. This is used to create properties in a ResourceInterface that point to a resource collection.
15+
* @param Item The type of the items in the collection.
16+
* @param Params Parameters that can be passed to the request, e.g. to filter the collection.
17+
* @param Self The type of the collection itself. This is used to be able to create additional fields
18+
* besides items, allItems on the collection itself.
19+
*/
20+
export type CollectionReference<
21+
Item extends ResourceInterface<Item>,
22+
Params = undefined,
23+
Self extends CollectionInterface<Item, Self> = CollectionInterface<Item>,
24+
> = Params extends undefined
25+
? () => CollectionInterface<Item, Self>
26+
: (params: Params) => CollectionInterface<Item, Self>;

src/interfaces/ResourceInterface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ interface ResourceInterface<ResourceType extends ResourceInterface = any> {
2323
$href: (relation: string, templateParams: Record<string, string | number | boolean>) => Promise<string | undefined>
2424
}
2525

26+
/**
27+
* Generic interface for a ResourceInterface without own store entry and a self link. To reload this resource, the
28+
* owning resource has to be reloaded.
29+
*/
2630
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2731
interface VirtualResource<Type extends ResourceInterface = any> extends ResourceInterface<Type> {
2832
_storeData: VirtualStoreData<Type>

tests/typescript/typecheck.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,13 @@ import { createStore, Store } from 'vuex'
44
import HalJsonVuexPlugin from '../../src/HalJsonVuexPlugin'
55
import { State } from '../../src/storeModule'
66

7-
import type CollectionInterface from '../../src/interfaces/CollectionInterface'
8-
import type ResourceInterface from '../../src/interfaces/ResourceInterface'
9-
107
/* eslint-disable no-unused-expressions */
118

12-
export type ResourceReference<T extends ResourceInterface<T>> = () => T;
13-
14-
export type CollectionType<
15-
Item extends ResourceInterface<Item>,
16-
Self extends CollectionInterface<Item, Self> = CollectionInterface<Item>,
17-
> = CollectionInterface<Item, Self>;
9+
import type ResourceInterface from '../../src/interfaces/ResourceInterface'
10+
import type { ResourceReference, CollectionReference } from '../../src/interfaces/References'
1811

19-
type SingleEndpointResource<T extends ResourceInterface<T>> = (params: { id: string }) => T;
20-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21-
type QueryEndpointResources<T extends ResourceInterface<T>, Param = Record<string, any>> = (
22-
params?: Param,
23-
) => CollectionType<T>;
12+
type SingleEndpointResource<T extends ResourceInterface<T>> = ResourceReference<T, { id: string }>;
13+
type QueryEndpointResources<T extends ResourceInterface<T>, Params = undefined> = CollectionReference<T, Params>;
2414

2515
interface PeriodEntity extends ResourceInterface<PeriodEntity> {
2616
name: string

0 commit comments

Comments
 (0)