From a9255d5e471f51e0591268034f11b500f70d1a20 Mon Sep 17 00:00:00 2001 From: Manuel Meister Date: Thu, 25 Apr 2024 15:14:47 +0200 Subject: [PATCH] Add generics to for storeData contents --- src/Collection.ts | 22 ++++++------- src/LoadingCollection.ts | 6 ++-- src/LoadingResource.ts | 28 ++++++++-------- src/Resource.ts | 14 ++++---- src/ResourceCreator.ts | 15 +++++---- src/halHelpers.ts | 6 ++-- src/index.ts | 47 ++++++++++++++------------- src/interfaces/CollectionInterface.ts | 10 +++--- src/interfaces/ResourceInterface.ts | 16 ++++----- src/interfaces/StoreData.ts | 14 ++++---- src/normalizeEntityUri.ts | 2 +- src/storeModule.ts | 20 ++++++------ 12 files changed, 101 insertions(+), 99 deletions(-) diff --git a/src/Collection.ts b/src/Collection.ts index 77653e3c..a3388578 100644 --- a/src/Collection.ts +++ b/src/Collection.ts @@ -8,45 +8,45 @@ import Resource from './Resource' /** * Filter out items that are marked as deleting (eager removal) */ -function filterDeleting (array: Array): Array { +function filterDeleting (array: Array>): Array> { return array.filter(entry => !entry._meta.deleting) } -class Collection extends Resource { +class Collection extends Resource> { /** * Get items excluding ones marked as 'deleting' (eager remove) * The items property should always be a getter, in order to make the call to mapArrayOfEntityReferences * lazy, since that potentially fetches a large number of entities from the API. */ - public get items (): Array { + public get items (): Array> { return filterDeleting(this._mapArrayOfEntityReferences(this._storeData.items)) } /** * Get all items including ones marked as 'deleting' (lazy remove) */ - public get allItems (): Array { + public get allItems (): Array> { return this._mapArrayOfEntityReferences(this._storeData.items) } /** * Returns a promise that resolves to the collection object, once all items have been loaded */ - public $loadItems () :Promise { + public $loadItems () :Promise> { return this._itemLoader(this._storeData.items) } /** * Returns a promise that resolves to the collection object, once all items have been loaded */ - private _itemLoader (array: Array) : Promise { + private _itemLoader (array: Array) : Promise> { if (!this._containsUnknownEntityReference(array)) { - return Promise.resolve(this as unknown as CollectionInterface) // we know that this object must be of type CollectionInterface + return Promise.resolve(this as unknown as CollectionInterface) // we know that this object must be of type CollectionInterface } // eager loading of 'fetchAllUri' (e.g. parent for embedded collections) if (this.config.avoidNPlusOneRequests) { - return this.apiActions.reload(this as unknown as CollectionInterface) as Promise // we know that reload resolves to a type CollectionInterface + return this.apiActions.reload(this as unknown as CollectionInterface) as Promise> // we know that reload resolves to a type CollectionInterface // no eager loading: replace each reference (Link) with a Resource (ResourceInterface) } else { @@ -54,7 +54,7 @@ class Collection extends Resource { return Promise.all( arrayWithReplacedReferences.map(entry => entry._meta.load) - ).then(() => this as unknown as CollectionInterface) // we know that this object must be of type CollectionInterface + ).then(() => this as unknown as CollectionInterface) // we know that this object must be of type CollectionInterface } } @@ -68,7 +68,7 @@ class Collection extends Resource { * @returns array the new array with replaced items, or a LoadingCollection if any of the array * elements is still loading. */ - private _mapArrayOfEntityReferences (array: Array): Array { + private _mapArrayOfEntityReferences (array: Array): Array> { if (!this._containsUnknownEntityReference(array)) { return this._replaceEntityReferences(array) } @@ -88,7 +88,7 @@ class Collection extends Resource { /** * Replace each item in array with a proper Resource (or LoadingResource) */ - private _replaceEntityReferences (array: Array): Array { + private _replaceEntityReferences (array: Array): Array> { return array .filter(entry => isEntityReference(entry)) .map(entry => this.apiActions.get(entry.href)) diff --git a/src/LoadingCollection.ts b/src/LoadingCollection.ts index 749fa3c2..2d244bae 100644 --- a/src/LoadingCollection.ts +++ b/src/LoadingCollection.ts @@ -9,7 +9,7 @@ class LoadingCollection { * @param loadArray Promise that resolves once the array has finished loading * @param existingContent optionally set the elements that are already known, for random access */ - static create (loadArray: Promise | undefined>, existingContent: Array = []): Array { + static create (loadArray: Promise> | undefined>, existingContent: Array> = []): Array> { // if Promsise resolves to undefined, provide empty array // this could happen if items is accessed from a LoadingResource, which resolves to a normal entity without 'items' const loadArraySafely = loadArray.then(array => array ?? []) @@ -19,7 +19,7 @@ class LoadingCollection { singleResultFunctions.forEach(func => { // eslint-disable-next-line @typescript-eslint/no-explicit-any existingContent[func] = (...args: any[]) => { - const resultLoaded = loadArraySafely.then(array => array[func](...args) as ResourceInterface) + const resultLoaded = loadArraySafely.then(array => array[func](...args) as ResourceInterface) return new LoadingResource(resultLoaded) } }) @@ -29,7 +29,7 @@ class LoadingCollection { arrayResultFunctions.forEach(func => { // eslint-disable-next-line @typescript-eslint/no-explicit-any existingContent[func] = (...args: any[]) => { - const resultLoaded = loadArraySafely.then(array => array[func](...args) as Array) // TODO: return type for .map() is not necessarily an Array + const resultLoaded = loadArraySafely.then(array => array[func](...args) as Array>) // TODO: return type for .map() is not necessarily an Array return LoadingCollection.create(resultLoaded) } }) diff --git a/src/LoadingResource.ts b/src/LoadingResource.ts index 3e7df1fd..2a383bd0 100644 --- a/src/LoadingResource.ts +++ b/src/LoadingResource.ts @@ -15,15 +15,15 @@ import { InternalConfig } from './interfaces/Config' * let user = new LoadingResource(...) * 'The "' + user + '" is called "' + user.name + '"' // gives 'The "" is called ""' */ -class LoadingResource implements ResourceInterface { +class LoadingResource implements ResourceInterface { public _meta: { self: string | null, selfUrl: string | null, - load: Promise + load: Promise> loading: boolean } - private loadResource: Promise + private loadResource: Promise> /** * @param loadResource a Promise that resolves to a Resource when the entity has finished @@ -32,7 +32,7 @@ class LoadingResource implements ResourceInterface { * returned LoadingResource will return it in calls to .self and ._meta.self * @param config configuration of this instance of hal-json-vuex */ - constructor (loadResource: Promise, self: string | null = null, config: InternalConfig | null = null) { + constructor (loadResource: Promise>, self: string | null = null, config: InternalConfig | null = null) { this._meta = { self: self, selfUrl: self ? config?.apiRoot + self : null, @@ -43,7 +43,7 @@ class LoadingResource implements ResourceInterface { this.loadResource = loadResource const handler = { - get: function (target: LoadingResource, prop: string | number | symbol) { + get: function (target: LoadingResource, prop: string | number | symbol) { // This is necessary so that Vue's reactivity system understands to treat this LoadingResource // like a normal object. if (prop === Symbol.toPrimitive) { @@ -80,28 +80,28 @@ class LoadingResource implements ResourceInterface { return new Proxy(this, handler) } - get items (): Array { - return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).items)) + get items (): Array> { + return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).items)) } - get allItems (): Array { - return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).allItems)) + get allItems (): Array> { + return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).allItems)) } - public $reload (): Promise { + public $reload (): Promise> { // Skip reloading entities that are already loading return this._meta.load } - public $loadItems (): Promise { - return this._meta.load.then(resource => (resource as CollectionInterface).$loadItems()) + public $loadItems (): Promise> { + return this._meta.load.then(resource => (resource as CollectionInterface).$loadItems()) } - public $post (data: unknown): Promise { + public $post (data: unknown): Promise | null> { return this._meta.load.then(resource => resource.$post(data)) } - public $patch (data: unknown): Promise { + public $patch (data: unknown): Promise> { return this._meta.load.then(resource => resource.$patch(data)) } diff --git a/src/Resource.ts b/src/Resource.ts index 2d01a0da..d26bf2fe 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -2,7 +2,7 @@ import urltemplate from 'url-template' import { isTemplatedLink, isVirtualLink, isEntityReference } from './halHelpers' import ResourceInterface from './interfaces/ResourceInterface' import ApiActions from './interfaces/ApiActions' -import { StoreData } from './interfaces/StoreData' +import { StoreData, StoreDataEntity } from './interfaces/StoreData' import ResourceCreator from './ResourceCreator' import { InternalConfig } from './interfaces/Config' @@ -11,11 +11,11 @@ import { InternalConfig } from './interfaces/Config' * If the storeData has been loaded into the store before but is currently reloading, the old storeData will be * returned, along with a ._meta.load promise that resolves when the reload is complete. */ -class Resource implements ResourceInterface { +class Resource = StoreDataEntity> implements ResourceInterface { public _meta: { self: string, selfUrl: string, - load: Promise + load: Promise> loading: boolean } @@ -59,7 +59,7 @@ class Resource implements ResourceInterface { // Use a trivial load promise to break endless recursion, except if we are currently reloading the storeData from the API const loadResource = storeData._meta.reloading - ? (storeData._meta.load as Promise).then(reloadedData => resourceCreator.wrap(reloadedData)) + ? (storeData._meta.load as Promise).then(reloadedData => resourceCreator.wrap(reloadedData)) : Promise.resolve(this) // Use a shallow clone of _meta, since we don't want to overwrite the ._meta.load promise or self link in the Vuex store @@ -71,15 +71,15 @@ class Resource implements ResourceInterface { } } - $reload (): Promise { + $reload (): Promise> { return this.apiActions.reload(this) } - $post (data: unknown): Promise { + $post (data: unknown): Promise | null> { return this.apiActions.post(this._meta.self, data) } - $patch (data: unknown): Promise { + $patch (data: unknown): Promise> { return this.apiActions.patch(this._meta.self, data) } diff --git a/src/ResourceCreator.ts b/src/ResourceCreator.ts index bc395301..c5308afe 100644 --- a/src/ResourceCreator.ts +++ b/src/ResourceCreator.ts @@ -6,6 +6,7 @@ import { StoreData } from './interfaces/StoreData' import ResourceInterface from './interfaces/ResourceInterface' import Collection from './Collection' import { isCollection } from './halHelpers' +import CollectionInterface from '@/interfaces/CollectionInterface' class ResourceCreator { private config: InternalConfig @@ -43,28 +44,28 @@ class ResourceCreator { * @param data entity data from the Vuex store * @returns object wrapped entity ready for use in a frontend component */ - wrap (data: StoreData): ResourceInterface { + wrap (data: StoreData): ResourceInterface { const meta = data._meta || { load: Promise.resolve(), loading: false } // Resource is loading --> return LoadingResource if (meta.loading) { - const loadResource = (meta.load as Promise).then(storeData => this.wrapData(storeData)) + const loadResource = (meta.load as Promise>).then(storeData => this.wrapData(storeData)) return new LoadingResource(loadResource, meta.self, this.config) // Resource is not loading --> wrap actual data } else { - return this.wrapData(data) + return this.wrapData(data) } } - wrapData (data: StoreData): ResourceInterface { + wrapData (data: StoreData): ResourceInterface | CollectionInterface { // Store data looks like a collection --> return CollectionInterface - if (isCollection(data)) { - return new Collection(data, this.apiActions, this, this.config) // these parameters are passed to Resource constructor + if (isCollection(data)) { + return new Collection(data, this.apiActions, this, this.config) // these parameters are passed to Resource constructor // else Store Data looks like an entity --> return normal Resource } else { - return new Resource(data, this.apiActions, this, this.config) + return new Resource(data, this.apiActions, this, this.config) } } } diff --git a/src/halHelpers.ts b/src/halHelpers.ts index 5373da86..fc74e47e 100644 --- a/src/halHelpers.ts +++ b/src/halHelpers.ts @@ -47,8 +47,8 @@ function isVirtualLink (object: keyValueObject): object is VirtualLink { * @param resource * @returns boolean true if resource is a VirtualResource */ -function isVirtualResource (resource: ResourceInterface): resource is VirtualResource { - return (resource as VirtualResource)._storeData?._meta?.virtual +function isVirtualResource (resource: ResourceInterface): resource is VirtualResource { + return (resource as VirtualResource)._storeData?._meta?.virtual as boolean } /** @@ -56,7 +56,7 @@ function isVirtualResource (resource: ResourceInterface): resource is VirtualRes * @param object to be examined * @returns boolean true if the object looks like a standalone collection, false otherwise */ -function isCollection (object: keyValueObject): object is StoreDataCollection { +function isCollection (object: keyValueObject): object is StoreDataCollection { return !!(object && Array.isArray(object.items)) } diff --git a/src/index.ts b/src/index.ts index bb21e932..ad31ecaf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,12 +26,13 @@ import { isVirtualResource } from './halHelpers' */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -function HalJsonVuex (store: Store>, axios: AxiosInstance, options: ExternalConfig): any { +function HalJsonVuex (store: Store>, axios: AxiosInstance, options: ExternalConfig): any { const defaultOptions = { apiName: 'api', avoidNPlusOneRequests: true, forceRequestedSelfLink: false } + const opts = { ...defaultOptions, ...options, apiRoot: axios.defaults.baseURL } store.registerModule(opts.apiName, { state: {}, ...storeModule }) @@ -46,7 +47,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns Promise resolves when the POST request has completed and the entity is available * in the Vuex store. */ - function post (uriOrCollection: string | ResourceInterface, data: unknown): Promise { + function post (uriOrCollection: string | ResourceInterface, data: unknown): Promise | null> { const uri = normalizeEntityUri(uriOrCollection, axios.defaults.baseURL) if (uri === null) { return Promise.reject(new Error(`Could not perform POST, "${uriOrCollection}" is not an entity or URI`)) @@ -96,7 +97,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * dummy is returned, which will be replaced with the true data through Vue's reactivity * system as soon as the API request finishes. */ - function get (uriOrEntity: string | ResourceInterface = ''): ResourceInterface { + function get (uriOrEntity: string | ResourceInterface = ''): ResourceInterface { const uri = normalizeEntityUri(uriOrEntity, axios.defaults.baseURL) if (uri === null) { @@ -109,7 +110,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, } setLoadPromiseOnStore(uri, load(uri, false)) - return resourceCreator.wrap(store.state[opts.apiName][uri]) + return resourceCreator.wrap(store.state[opts.apiName][uri]) } /** @@ -122,11 +123,11 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns Promise Resolves when the GET request has completed and the updated entity is available * in the Vuex store. */ - async function reload (uriOrEntity: string | ResourceInterface): Promise { - let resource: ResourceInterface + async function reload (uriOrEntity: string | ResourceInterface): Promise> { + let resource: ResourceInterface if (typeof uriOrEntity === 'string') { - resource = get(uriOrEntity) + resource = get(uriOrEntity) } else { resource = uriOrEntity } @@ -144,7 +145,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, throw new Error(`Could not perform reload, "${uriOrEntity}" is not an entity or URI`) } - const loadPromise = load(uri, true) + const loadPromise = load(uri, true) // Catch all errors for the Promise that is saved to the store, to avoid unhandled promise rejections. // The errors are still available to catch on the promise returned by reload. setLoadPromiseOnStore(uri, loadPromise.catch(() => { @@ -170,7 +171,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns entity the current entity data from the Vuex store. Note: This may be a reactive dummy if the * API request is still ongoing. */ - function load (uri: string, forceReload: boolean): Promise { + function load (uri: string, forceReload: boolean): Promise> { const existsInStore = !isUnknown(uri) const isAlreadyLoading = existsInStore && (store.state[opts.apiName][uri]._meta || {}).loading @@ -187,9 +188,9 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, } if (!existsInStore) { - return loadFromApi(uri, 'fetch') + return loadFromApi(uri, 'fetch') } else if (forceReload) { - return loadFromApi(uri, 'reload').catch(error => { + return loadFromApi(uri, 'reload').catch(error => { store.commit('reloadingFailed', uri) throw error }) @@ -208,7 +209,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns Promise resolves to the raw data stored in the Vuex store after the API request completes, or * rejects when the API request fails */ - function loadFromApi (uri: string, operation: string): Promise { + function loadFromApi (uri: string, operation: string): Promise> { return axios.get(uri || '/').then(({ data }) => { if (opts.forceRequestedSelfLink) { data._links.self.href = uri @@ -228,8 +229,8 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @param templateParams in case the relation is a templated link, the template parameters that should be filled in * @returns Promise resolves to the URI of the related entity. */ - async function href (uriOrEntity: string | ResourceInterface, relation: string, templateParams:Record = {}): Promise { - const selfUri = normalizeEntityUri(await get(uriOrEntity)._meta.load, axios.defaults.baseURL) + async function href (uriOrEntity: string | ResourceInterface, relation: string, templateParams:Record = {}): Promise { + const selfUri = normalizeEntityUri(await get(uriOrEntity)._meta.load, axios.defaults.baseURL) const rel = selfUri != null ? store.state[opts.apiName][selfUri][relation] : null if (!rel || !rel.href) return undefined if (rel.templated) { @@ -245,7 +246,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns Promise resolves when the PATCH request has completed and the updated entity is available * in the Vuex store. */ - function patch (uriOrEntity: string | ResourceInterface, data: unknown) : Promise { + function patch (uriOrEntity: string | ResourceInterface, data: unknown) : Promise> { const uri = normalizeEntityUri(uriOrEntity, axios.defaults.baseURL) if (uri === null) { return Promise.reject(new Error(`Could not perform PATCH, "${uriOrEntity}" is not an entity or URI`)) @@ -253,7 +254,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, const existsInStore = !isUnknown(uri) if (existsInStore) { - const entity = get(uri) + const entity = get(uri) if (isVirtualResource(entity)) { return Promise.reject(new Error('patch is not implemented for virtual resources')) } @@ -268,7 +269,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, data._links.self.href = uri } storeHalJsonData(data) - return get(uri) + return get(uri) }, (error) => { throw handleAxiosError('patch', uri, error) }) @@ -282,7 +283,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * immediately re-fetch the purged entity from the API in order to re-display it. * @param uriOrEntity URI (or instance) of an entity which should be removed from the Vuex store */ - function purge (uriOrEntity: string | ResourceInterface): void { + function purge (uriOrEntity: string | ResourceInterface): void { const uri = normalizeEntityUri(uriOrEntity, axios.defaults.baseURL) if (uri === null) { // Can't purge an unknown URI, do nothing @@ -311,7 +312,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @returns Promise resolves when the DELETE request has completed and either all related entites have * been reloaded from the API, or the failed deletion has been cleaned up. */ - function del (uriOrEntity: string | ResourceInterface): Promise { + function del (uriOrEntity: string | ResourceInterface): Promise { const uri = normalizeEntityUri(uriOrEntity, axios.defaults.baseURL) if (uri === null) { // Can't delete an unknown URI, do nothing @@ -319,7 +320,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, } if (!isUnknown(uri)) { - const entity = get(uri) + const entity = get(uri) if (isVirtualResource(entity)) { return Promise.reject(new Error('del is not implemented for virtual resources')) } @@ -347,7 +348,7 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, return objectKeys.length === 1 && objectKeys[0] === 'href' && (value as Link).href === uri } - function findEntitiesReferencing (uri: string) : Array { + function findEntitiesReferencing (uri: string) : Array> { return Object.values(store.state[opts.apiName]) .filter((entity) => { return Object.values(entity).some(propertyValue => @@ -403,8 +404,8 @@ function HalJsonVuex (store: Store>, axios: AxiosInstance, * @param uri * @param loadStoreData */ - function setLoadPromiseOnStore (uri: string, loadStoreData: Promise | null = null) { - const promise: SerializablePromise = loadStoreData || Promise.resolve(store.state[opts.apiName][uri]) + function setLoadPromiseOnStore (uri: string, loadStoreData: Promise> | null = null) { + const promise: SerializablePromise> = loadStoreData || Promise.resolve(store.state[opts.apiName][uri]) promise.toJSON = () => '{}' // avoid warning in Nuxt when serializing the complete Vuex store ("Cannot stringify arbitrary non-POJOs Promise") store.state[opts.apiName][uri]._meta.load = promise } diff --git a/src/interfaces/CollectionInterface.ts b/src/interfaces/CollectionInterface.ts index d61e6159..1795b60e 100644 --- a/src/interfaces/CollectionInterface.ts +++ b/src/interfaces/CollectionInterface.ts @@ -1,12 +1,12 @@ import ResourceInterface from './ResourceInterface' import { StoreDataCollection } from './StoreData' -interface CollectionInterface extends ResourceInterface { - _storeData: StoreDataCollection +interface CollectionInterface extends ResourceInterface { + _storeData: StoreDataCollection - items: Array - allItems: Array - $loadItems: () => Promise + items: Array> + allItems: Array> + $loadItems: () => Promise> } export default CollectionInterface diff --git a/src/interfaces/ResourceInterface.ts b/src/interfaces/ResourceInterface.ts index 13ca9305..06893eef 100644 --- a/src/interfaces/ResourceInterface.ts +++ b/src/interfaces/ResourceInterface.ts @@ -4,26 +4,26 @@ import { StoreData, VirtualStoreData } from './StoreData' * Generic interface for a standalone ResourceInterface (e.g. a HAl resource with an own store entry and a self link) * Can be a collection or a single entity */ -interface ResourceInterface { +interface ResourceInterface { _meta: { self: string | null selfUrl: string | null - load: Promise + load: Promise> loading: boolean deleting?: boolean } - _storeData?: StoreData // optional, because LoadingResource has no _storeData + _storeData?: StoreData // optional, because LoadingResource has no _storeData - $reload: () => Promise - $post: (data: unknown) => Promise - $patch: (data: unknown) => Promise + $reload: () => Promise> + $post: (data: unknown) => Promise | null> + $patch: (data: unknown) => Promise> $del: () => Promise $href: (relation: string, templateParams: Record) => Promise } -interface VirtualResource extends ResourceInterface { - _storeData: VirtualStoreData +interface VirtualResource extends ResourceInterface { + _storeData: VirtualStoreData } export { ResourceInterface, VirtualResource } diff --git a/src/interfaces/StoreData.ts b/src/interfaces/StoreData.ts index 68629e14..b403fa5d 100644 --- a/src/interfaces/StoreData.ts +++ b/src/interfaces/StoreData.ts @@ -23,7 +23,7 @@ type StoreDataMeta = { } } -type VirtualStoreDataMeta = StoreDataMeta & { +type VirtualStoreDataMeta = { _meta: { virtual: boolean owningResource: string @@ -31,22 +31,22 @@ type VirtualStoreDataMeta = StoreDataMeta & { } } -type StoreDataEntity = StoreDataMeta & { +type StoreDataEntity = Type & StoreDataMeta & { _meta: { - load: SerializablePromise + load: SerializablePromise> } } -type StoreDataCollection = StoreDataMeta & { +type StoreDataCollection = Type & StoreDataMeta & { items: Array, _meta: { - load: SerializablePromise + load: SerializablePromise> } } -type StoreData = StoreDataEntity | StoreDataCollection +type StoreData = StoreDataEntity | StoreDataCollection -type VirtualStoreData = StoreData & VirtualStoreDataMeta +type VirtualStoreData = VirtualStoreDataMeta & StoreData export { StoreData, VirtualStoreData, Link, VirtualLink, TemplatedLink, StoreDataEntity, StoreDataCollection, SerializablePromise } diff --git a/src/normalizeEntityUri.ts b/src/normalizeEntityUri.ts index a42b93c3..e7914dd3 100644 --- a/src/normalizeEntityUri.ts +++ b/src/normalizeEntityUri.ts @@ -35,7 +35,7 @@ function sortQueryParams (uri: string): string { * @param baseUrl common URI prefix to remove during normalization * @returns {null|string} normalized URI, or null if the uriOrEntity argument was not understood */ -function normalizeEntityUri (uriOrEntity: string | ResourceInterface | null = '', baseUrl = ''): string | null { +function normalizeEntityUri (uriOrEntity: string | ResourceInterface | null = '', baseUrl = ''): string | null { let uri if (typeof uriOrEntity === 'string') { diff --git a/src/storeModule.ts b/src/storeModule.ts index 3db9bb49..4c0363a2 100644 --- a/src/storeModule.ts +++ b/src/storeModule.ts @@ -3,16 +3,16 @@ import StoreData from './interfaces/StoreData' import { MutationTree } from 'vuex/types' export const state = {} -export type State = Record +export type State = Record> -export const mutations: MutationTree = { +export const mutations: MutationTree> = { /** * Adds a placeholder into the store that indicates that the entity with the given URI is currently being * fetched from the API and not yet available. * @param state Vuex state * @param uri URI of the object that is being fetched */ - addEmpty (state: State, uri: string) : void { + addEmpty (state: State, uri: string) : void { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore state[uri] = { _meta: { self: uri, loading: true } } @@ -22,7 +22,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param data An object mapping URIs to entities that should be merged into the Vuex state. */ - add (state: State, data: Record) : void { + add (state: State, data: Record) : void { Object.keys(data).forEach(uri => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -37,7 +37,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity that is currently being reloaded */ - reloading (state: State, uri: string) : void { + reloading (state: State, uri: string) : void { if (state[uri]) state[uri]._meta.reloading = true }, /** @@ -45,7 +45,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity that is currently being reloaded */ - reloadingFailed (state: State, uri: string) : void { + reloadingFailed (state: State, uri: string) : void { if (state[uri]) state[uri]._meta.reloading = false }, /** @@ -53,7 +53,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity to be removed */ - purge (state: State, uri: string) : void { + purge (state: State, uri: string) : void { delete state[uri] }, /** @@ -61,7 +61,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity to be removed */ - purgeAll (state: State) : void { + purgeAll (state: State) : void { Object.keys(state).forEach(uri => { delete state[uri] }) @@ -71,7 +71,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity that is currently being deleted */ - deleting (state: State, uri: string) : void { + deleting (state: State, uri: string) : void { if (state[uri]) state[uri]._meta.deleting = true }, /** @@ -79,7 +79,7 @@ export const mutations: MutationTree = { * @param state Vuex state * @param uri URI of the entity that failed to be deleted */ - deletingFailed (state: State, uri: string) : void { + deletingFailed (state: State, uri: string) : void { if (state[uri]) state[uri]._meta.deleting = false } }