From 664037c44a0cf87df952474485ca2da00d5f03a8 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Tue, 29 Sep 2026 16:14:06 +0800 Subject: [PATCH] refactor(nextui): type check sorts for series and books --- next-ui/src/composables/section.ts | 15 ++++++++------- next-ui/src/composables/sort.ts | 4 ++-- next-ui/src/functions/sort.ts | 4 ++-- next-ui/src/types/sort.ts | 23 ++++++++++++++++++++--- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/next-ui/src/composables/section.ts b/next-ui/src/composables/section.ts index 9f935118..e6edab22 100644 --- a/next-ui/src/composables/section.ts +++ b/next-ui/src/composables/section.ts @@ -6,6 +6,7 @@ import type { SearchConditionBook, SearchConditionSeries } from '@/generated/ope import { seriesListQueryInfinite, seriesUpdatedQueryInfinite } from '@/colada/series' import type { OverviewSection } from '@/types/OverviewSection' import type { Sort } from '@/types/PageRequest' +import type { SortBook, SortSeries } from '@/types/sort' export function useOverviewSection( section: MaybeRefOrGetter, @@ -15,19 +16,19 @@ export function useOverviewSection( const sort = computed(() => { switch (toValue(section)) { case 'on_deck': - return [] + return [] satisfies SortBook[] case 'keep_reading': - return [{ key: 'readProgress.readDate', order: 'desc' }] + return [{ key: 'readProgress.readDate', order: 'desc' }] satisfies SortBook[] case 'recently_released_books': - return [{ key: 'metadata.releaseDate', order: 'desc' }] + return [{ key: 'metadata.releaseDate', order: 'desc' }] satisfies SortBook[] case 'recently_added_books': - return [{ key: 'createdDate', order: 'desc' }] + return [{ key: 'createdDate', order: 'desc' }] satisfies SortBook[] case 'recently_read_books': - return [{ key: 'readProgress.readDate', order: 'desc' }] + return [{ key: 'readProgress.readDate', order: 'desc' }] satisfies SortBook[] case 'recently_added_series': - return [{ key: 'createdDate', order: 'desc' }] + return [{ key: 'createdDate', order: 'desc' }] satisfies SortSeries[] case 'recently_updated_series': - return [{ key: 'lastModifiedDate', order: 'desc' }] + return [{ key: 'lastModifiedDate', order: 'desc' }] satisfies SortSeries[] } }) diff --git a/next-ui/src/composables/sort.ts b/next-ui/src/composables/sort.ts index 04e6d526..094f08f9 100644 --- a/next-ui/src/composables/sort.ts +++ b/next-ui/src/composables/sort.ts @@ -1,6 +1,6 @@ import { useRouteQuerySchema } from '@/composables/useRouteQuerySchema' import { type Sort } from '@/types/PageRequest' -import { MultiSortSchema, sortOptionToSorts, stringifySort } from '@/functions/sort' +import { MultiSortSchema, sortDefinitionToSorts, stringifySort } from '@/functions/sort' import { deepEqual } from 'fast-equals' import type { SortOption } from '@/types/sort' @@ -17,7 +17,7 @@ export function useSort(defaultSort: Sort[], options: SortOption[], multiSort: b defaultSort, ).data - const validSorts = options.flatMap((it) => sortOptionToSorts(it)) + const validSorts = options.flatMap((it) => sortDefinitionToSorts(it)) // filter out invalid values watch( diff --git a/next-ui/src/functions/sort.ts b/next-ui/src/functions/sort.ts index f8b2faef..0a180f5c 100644 --- a/next-ui/src/functions/sort.ts +++ b/next-ui/src/functions/sort.ts @@ -1,6 +1,6 @@ import type { Sort } from '@/types/PageRequest' import * as v from 'valibot' -import type { SortOption } from '@/types/sort' +import type { SortDefinition } from '@/types/sort' /** * Creates a compare function for Array.prototype.sort() @@ -53,7 +53,7 @@ export function stringifySort(sort: Sort): string { return `${sort.key},${sort.order || 'asc'}` } -export function sortOptionToSorts(option: SortOption): Sort[] { +export function sortDefinitionToSorts(option: SortDefinition): Sort[] { const sorts: Sort[] = [ { key: option.key, diff --git a/next-ui/src/types/sort.ts b/next-ui/src/types/sort.ts index e02c191b..c16ec008 100644 --- a/next-ui/src/types/sort.ts +++ b/next-ui/src/types/sort.ts @@ -1,8 +1,6 @@ import { defineMessage, type MessageDescriptor } from 'vue-intl' -export type SortOption = { - // for display - label: string +export type SortDefinition = { // sorting key sent to API key: string // initial order @@ -11,10 +9,27 @@ export type SortOption = { invertible: boolean } +export type SortOption = { + // for display + label: string +} & SortDefinition + export type SortOrder = 'asc' | 'desc' export type SortOptionDescriptor = Omit & { message: MessageDescriptor } +type ResolveOrder = { + [K in keyof T]: T[K] extends { + key: infer KKey extends string + initialOrder: infer KOrder + invertible: infer KInvert + } + ? KInvert extends true + ? { key: KKey; order: SortOrder } + : { key: KKey; order: KOrder } + : never +}[number] + const messages = { createdDate: defineMessage({ description: 'Sort label: createdDate', @@ -105,6 +120,7 @@ export const sortSeries = [ ] as const satisfies readonly SortOptionDescriptor[] export type SortKeysSeries = (typeof sortSeries)[number]['key'] +export type SortSeries = ResolveOrder export const sortBooks = [ { @@ -198,3 +214,4 @@ export const sortBooks = [ ] as const satisfies readonly SortOptionDescriptor[] export type SortKeysBook = (typeof sortBooks)[number]['key'] +export type SortBook = ResolveOrder