Skip to content

Commit 04131d3

Browse files
committed
feat(async-stack): better generics and typing
1 parent a39dd39 commit 04131d3

5 files changed

Lines changed: 59 additions & 51 deletions

File tree

.changeset/green-experts-crash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@svelte-put/async-stack': minor
3+
---
4+
5+
simplify generics, `Stack.pop` now returns `StackItem | null`

packages/async-stack/src/stack-builder.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,27 @@ import { Stack } from './stack.svelte.js';
44
* @template {Record<string, import('svelte').Component>} [VariantMap={}]
55
*/
66
export class StackBuilder {
7-
/** @type {Record<string, import('./types').StackItemVariantConfig<any, any, any>>} */
7+
/** @type {Record<string, import('./types').StackItemVariantConfig<string, import('svelte').Component>>} */
88
#variantConfigMap = {};
99

1010
/**
11-
* @type {import('./types').StackItemCommonConfig<any, any, any> | undefined}
11+
* @type {import('./types').StackItemCommonConfig<string, import('svelte').Component> | undefined}
1212
*/
1313
#init;
1414

1515
/**
16-
* @param {import('./types').StackItemCommonConfig<any, any, any>} [init]
16+
* @param {import('./types').StackItemCommonConfig<string, import('svelte').Component>} [init]
1717
*/
1818
constructor(init) {
1919
this.#init = init;
2020
}
2121

2222
/**
2323
* add config for a stack item variant
24-
* @template Resolved
2524
* @template {string} Variant
2625
* @template {import('svelte').Component} UserComponent
2726
* @param {Variant} variant
28-
* @param {UserComponent | Omit<import('./types').StackItemVariantConfig<Resolved, Variant, UserComponent>, 'variant'>} config
27+
* @param {UserComponent | Omit<import('./types').StackItemVariantConfig<Variant, UserComponent>, 'variant'>} config
2928
* @returns {StackBuilder<VariantMap & Record<Variant, UserComponent>> }
3029
*/
3130
addVariant(variant, config) {
@@ -53,7 +52,7 @@ export class StackBuilder {
5352
}
5453

5554
/**
56-
* @param {import('./types').StackItemCommonConfig<any, any, any>} [init]
55+
* @param {import('./types').StackItemCommonConfig<string, import('svelte').Component>} [init]
5756
* @returns {StackBuilder}
5857
*/
5958
export function stack(init) {

packages/async-stack/src/stack-item.svelte.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/**
2-
* @template Resolved
3-
* @template {import('svelte').Component} [UserComponent=import('svelte').Component<import('./types.d.ts').StackItemProps<Resolved>>]
2+
* @template {import('svelte').Component} [UserComponent=import('svelte').Component]
3+
* @template [Resolved=import('./types.d.ts').ComponentResolved<UserComponent>]
44
*/
55
export class StackItem {
66
/** @type {import('./types.d.ts').StackItemState} */
77
// eslint-disable-next-line no-undef
88
state = $state('idle');
9-
/** @type {Required<import('./types.d.ts').StackItemInstanceConfig<Resolved, string, UserComponent>>} */
9+
/** @type {Required<import('./types.d.ts').StackItemInstanceConfig<string, UserComponent>>} */
1010
config;
1111

1212
#internals = {
@@ -25,7 +25,7 @@ export class StackItem {
2525
resolution;
2626

2727
/**
28-
* @param {Required<import('./types.d.ts').StackItemInstanceConfig<Resolved, string, UserComponent>>} config
28+
* @param {Required<import('./types.d.ts').StackItemInstanceConfig<string, UserComponent>>} config
2929
*/
3030
constructor(config) {
3131
this.config = config;

packages/async-stack/src/stack.svelte.js

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { StackItem } from './stack-item.svelte.js';
77
* @template {Record<string, import('svelte').Component>} [VariantMap={}]
88
*/
99
export class Stack {
10-
/** @type {Record<string, import('./types.d.ts').StackItemVariantConfig<any, any, any>>} */
10+
/** @type {Record<string, import('./types.d.ts').StackItemVariantConfig<string, import('svelte').Component>>} */
1111
#variantConfigMap = {};
1212
#counter = 0;
1313

@@ -19,7 +19,7 @@ export class Stack {
1919
items = $state([]);
2020

2121
/**
22-
* @type {Required<import('./types.d.ts').StackItemCommonConfig<any, any, any>>}
22+
* @type {Required<import('./types.d.ts').StackItemCommonConfig<string, import('svelte').Component>>}
2323
*/
2424
// eslint-disable-next-line no-undef
2525
config = $state({
@@ -48,8 +48,8 @@ export class Stack {
4848
};
4949

5050
/**
51-
* @param {Record<keyof VariantMap, import('./types.d.ts').StackItemVariantConfig<any, any, any>>} variantConfigMap
52-
* @param {import('./types.d.ts').StackItemCommonConfig<any, any, any>} [init]
51+
* @param {Record<keyof VariantMap, import('./types.d.ts').StackItemVariantConfig<string, import('svelte').Component>>} variantConfigMap
52+
* @param {import('./types.d.ts').StackItemCommonConfig<string, import('svelte').Component>} [init]
5353
*/
5454
constructor(variantConfigMap, init) {
5555
if (init?.id) this.config.id = init.id;
@@ -61,35 +61,33 @@ export class Stack {
6161
/**
6262
* @template {Extract<keyof VariantMap, string>} Variant
6363
* @template {VariantMap[Variant]} [UserComponent=VariantMap[Variant]]
64-
* @template [Resolved=undefined|Awaited<import('svelte').ComponentProps<UserComponent>['item']['resolution']>]
6564
* @overload
6665
* @param {Variant} variant
67-
* @param {import('./types.d.ts').StackItemByVariantPushConfig<Resolved, Variant, UserComponent>} [config]
68-
* @returns {StackItem<Resolved>}
66+
* @param {import('./types.d.ts').StackItemByVariantPushConfig<Variant, UserComponent>} [config]
67+
* @returns {StackItem<UserComponent>}
6968
*/
7069
/**
7170
* @template {import('svelte').Component} UserComponent
72-
* @template [Resolved=undefined|Awaited<import('svelte').ComponentProps<UserComponent>['item']['resolution']>]
7371
* @overload
7472
* @param {'custom'} variant
75-
* @param {import('./types.d.ts').StackItemCustomPushConfig<Resolved, UserComponent>} config
76-
* @returns {StackItem<Resolved>}
73+
* @param {import('./types.d.ts').StackItemCustomPushConfig<UserComponent>} config
74+
* @returns {StackItem<UserComponent>}
7775
*/
7876
/**
7977
* @param {string} variant
80-
* @param {import('./types.d.ts').StackItemByVariantPushConfig<any, string, import('svelte').Component> | import('./types.d.ts').StackItemCustomPushConfig<any, import('svelte').Component>} [config]
78+
* @param {import('./types.d.ts').StackItemByVariantPushConfig<string, import('svelte').Component> | import('./types.d.ts').StackItemCustomPushConfig<import('svelte').Component>} [config]
8179
* @returns {StackItem<any>}
8280
*/
8381
push(variant, config) {
8482
// STEP 1: resolve instance config, merge with common config and variant config, if any
85-
/** @type {import('./types.d.ts').StackItemInstanceConfig<any, any, any>} */
83+
/** @type {import('./types.d.ts').StackItemInstanceConfig<string, import('svelte').Component>} */
8684
let instanceConfig;
87-
/** @type {NonNullable<import('./types.d.ts').StackItemCommonConfig<Resolved, string, import('svelte').Component>['id']>} */
85+
/** @type {NonNullable<import('./types.d.ts').StackItemCommonConfig<string, import('svelte').Component>['id']>} */
8886
let idResolver;
8987

9088
if (variant === 'custom') {
9189
const rConfig =
92-
/** @type {import('./types.d.ts').StackItemCustomPushConfig<any, any>} */ (
90+
/** @type {import('./types.d.ts').StackItemCustomPushConfig<import('svelte').Component>} */ (
9391
config
9492
);
9593
if (!rConfig || !rConfig.component) {
@@ -151,21 +149,23 @@ export class Stack {
151149
}
152150

153151
/**
152+
* @template {import('svelte').Component} [UserComponent=import('svelte').Component]
154153
* @overload
155154
* @param {string} [id]
156155
* @param {any} [detail]
157-
* @returns {void}
156+
* @returns {StackItem<UserComponent> | null}
158157
*/
159158
/**
159+
* @template {import('svelte').Component} [UserComponent=import('svelte').Component]
160160
* @overload
161-
* @param {import('./types.d.ts').StackItemPopVerboseInput} [config]
162-
* @returns {void}
161+
* @param {import('./types.d.ts').StackItemPopVerboseInput<UserComponent>} [config]
162+
* @returns {StackItem<UserComponent> | null}
163163
*/
164164
/**
165-
*
166-
* @param {string | import('./types.d.ts').StackItemPopVerboseInput} [config]
165+
* @template {import('svelte').Component} [UserComponent=import('svelte').Component]
166+
* @param {string | import('./types.d.ts').StackItemPopVerboseInput<UserComponent>} [config]
167167
* @param {any} [resolved]
168-
* @returns {void}
168+
* @returns {StackItem<UserComponent> | null}
169169
*/
170170
pop(config, resolved) {
171171
/** @type {string | undefined} */
@@ -179,18 +179,20 @@ export class Stack {
179179
}
180180
}
181181

182-
/** @type {StackItem<any> | undefined} */
183-
let pushed;
182+
/** @type {StackItem<UserComponent> | null} */
183+
let pushed = null;
184184
if (id) {
185-
pushed = this.items.find((n) => n.config.id === id);
185+
pushed = this.items.find((n) => n.config.id === id) ?? null;
186186
} else {
187-
pushed = this.items.at(-1);
187+
pushed = this.items.at(-1) ?? null;
188188
}
189189

190190
if (pushed) {
191191
pushed.resolve(resolved);
192192
this.items = this.items.filter((n) => n.config.id !== pushed.config.id);
193193
}
194+
195+
return pushed;
194196
}
195197

196198
/**

packages/async-stack/src/types.d.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,17 @@ import { ActionReturn } from 'svelte/action';
44

55
import type { StackItem } from './stack-item.svelte.js';
66

7+
export declare type StackItemProps<Resolved> = {
8+
/** the stack item instance injected by the stack */
9+
item: Omit<StackItem<import('svelte').Component<StackItemProps<Resolved>>>, '#internals'>;
10+
};
11+
12+
export type ComponentResolved<UserComponent extends Component> =
13+
ComponentProps<UserComponent> extends StackItemProps<infer Resolved>
14+
? Resolved
15+
: any;
16+
717
export type StackItemCommonConfig<
8-
Resolved,
918
Variant extends string,
1019
UserComponent extends Component,
1120
> = {
@@ -25,21 +34,15 @@ export type StackItemCommonConfig<
2534
| 'counter'
2635
| 'uuid'
2736
| ((
28-
config: Required<Omit<StackItemInstanceConfig<Resolved, Variant, UserComponent>, 'id'>>,
37+
config: Required<Omit<StackItemInstanceConfig<Variant, UserComponent>, 'id'>>,
2938
) => string);
3039
};
3140

32-
export declare type StackItemProps<Resolved> = {
33-
/** the stack item instance injected by the stack */
34-
item: Omit<StackItem<Resolved>, '#internals'>;
35-
};
36-
3741
/** predefined variant config provided while building a {@link Stack} instance */
3842
export type StackItemVariantConfig<
39-
Resolved,
4043
Variant extends string,
4144
UserComponent extends Component,
42-
> = StackItemCommonConfig<Resolved, Variant, UserComponent> & {
45+
> = StackItemCommonConfig<Variant, UserComponent> & {
4346
/** string variant representing this config, must be unique within a {@link Stack} instance */
4447
variant: Variant;
4548
/** any Svelte component used for rendering stack item UI */
@@ -50,35 +53,34 @@ export type StackItemVariantConfig<
5053

5154
/** a resolved config for a {@link StackItemInstance} */
5255
export type StackItemInstanceConfig<
53-
Resolved,
5456
Variant extends string,
5557
UserComponent extends Component,
56-
> = Required<Omit<StackItemVariantConfig<Resolved, Variant, UserComponent>, 'id'>> & {
58+
> = Required<Omit<StackItemVariantConfig<Variant, UserComponent>, 'id'>> & {
5759
id: string;
5860
timeout: number;
5961
};
6062

6163
export type StackItemState = 'idle' | 'elapsing' | 'paused' | 'timeout' | 'resolved';
6264

6365
export type StackItemByVariantPushConfig<
64-
Resolved,
6566
Variant extends string,
6667
UserComponent extends Component,
67-
> = StackItemCommonConfig<Resolved, Variant, UserComponent> & {
68+
> = StackItemCommonConfig< Variant, UserComponent> & {
6869
props?: Omit<ComponentProps<UserComponent>, 'item'>;
6970
};
7071

7172
export type StackItemCustomPushConfig<
72-
Resolved,
7373
UserComponent extends Component,
74-
> = StackItemCommonConfig<Resolved, 'custom', UserComponent> & {
74+
> = StackItemCommonConfig<'custom', UserComponent> & {
7575
component: UserComponent;
7676
props?: Omit<ComponentProps<UserComponent>, 'item'>;
7777
};
7878

79-
export type StackItemPopVerboseInput = {
79+
export type StackItemPopVerboseInput <
80+
UserComponent extends Component,
81+
>= {
8082
id?: string;
81-
resolved?: any;
83+
resolved?: ComponentResolved<UserComponent>;
8284
};
8385

8486
export type StackItemRenderActionReturn = ActionReturn<StackItem<any>>;

0 commit comments

Comments
 (0)