11import ManyKeysMap from "many-keys-map" ;
22
3+ import type { DetectorResultType } from "./detectors.js" ;
34import {
5+ type InstanceOptions ,
46 type Options ,
57 type UserSideOptions ,
68 getDefaultOptions ,
79 mergeOptions ,
810} from "./options" ;
9- import type { QuerySelectorResult } from "./types.js" ;
11+ import type { QuerySelectorReturn } from "./types.js" ;
1012
1113const unifyCache = new ManyKeysMap < unknown , Promise < unknown > > ( ) ;
1214
13- type InitOptions = {
14- defaultOptions : Options ;
15- } ;
16-
17- export function createWaitElement ( initOptions : Partial < InitOptions > = { } ) {
18- const { defaultOptions = getDefaultOptions ( ) } = initOptions ;
19-
20- // FIXME: Generics like `<Result extends QuerySelectorResult>`, but incorrectly resolve types
21- return (
15+ export function createWaitElement <
16+ Instance_Result = unknown ,
17+ Instance_QuerySelectorResult extends
18+ QuerySelectorReturn = QuerySelectorReturn ,
19+ > (
20+ instanceOptions : InstanceOptions <
21+ Instance_Result ,
22+ Instance_QuerySelectorResult
23+ > ,
24+ ) {
25+ const { defaultOptions } = instanceOptions ;
26+
27+ return <
28+ Result = Instance_Result ,
29+ QuerySelectorResult extends QuerySelectorReturn = QuerySelectorReturn ,
30+ > (
2231 selector : string ,
23- options ?: UserSideOptions ,
24- ) : Promise < QuerySelectorResult > => {
32+ options ?: UserSideOptions < Result , QuerySelectorResult > ,
33+ ) : Promise < Result > => {
34+ // NOTE: defuはマージで優先した型へ絞り込んで返さずユニオン型で返すためキャストしている。`options?: UserSideOptions<Result,…>` のジェネリクスで実際には型は動的に解決されるため問題ない。
2535 const { target, unifyProcess, observeConfigs, detector, signal } =
26- mergeOptions ( defaultOptions , options ) ;
36+ mergeOptions ( options , defaultOptions ) as unknown as Options <
37+ Result ,
38+ QuerySelectorResult
39+ > ;
2740
2841 const unifyPromiseKey = [
2942 selector ,
@@ -37,10 +50,10 @@ export function createWaitElement(initOptions: Partial<InitOptions> = {}) {
3750 const cachedPromise = unifyCache . get ( unifyPromiseKey ) ;
3851
3952 if ( unifyProcess && cachedPromise ) {
40- return cachedPromise as Promise < QuerySelectorResult > ;
53+ return cachedPromise as Promise < Result > ;
4154 }
4255
43- const detectPromise = new Promise < QuerySelectorResult > (
56+ const detectPromise = new Promise < Result > (
4457 // biome-ignore lint/suspicious/noAsyncPromiseExecutor: avoid nesting promise
4558 async ( resolve , reject ) => {
4659 // reject if already aborted
@@ -56,15 +69,15 @@ export function createWaitElement(initOptions: Partial<InitOptions> = {}) {
5669 break ;
5770 }
5871
59- const { element , isDetected } = await detectElement ( {
72+ const detectResult = await detectElement ( {
6073 selector,
6174 target : target ,
6275 detector : detector ,
6376 } ) ;
6477
65- if ( isDetected ) {
78+ if ( detectResult . isDetected ) {
6679 observer . disconnect ( ) ;
67- resolve ( element ) ;
80+ resolve ( detectResult . result ) ;
6881 break ;
6982 }
7083 }
@@ -82,14 +95,14 @@ export function createWaitElement(initOptions: Partial<InitOptions> = {}) {
8295 ) ;
8396
8497 // Checking already element existed.
85- const { element , isDetected } = await detectElement ( {
98+ const detectResult = await detectElement ( {
8699 selector,
87100 target : target ,
88101 detector : detector ,
89102 } ) ;
90103
91- if ( isDetected ) {
92- return resolve ( element ) ;
104+ if ( detectResult . isDetected ) {
105+ return resolve ( detectResult . result ) ;
93106 }
94107
95108 // Start observe.
@@ -105,18 +118,25 @@ export function createWaitElement(initOptions: Partial<InitOptions> = {}) {
105118 } ;
106119}
107120
108- async function detectElement ( {
121+ async function detectElement <
122+ Result = unknown ,
123+ QuerySelectorResult extends QuerySelectorReturn = QuerySelectorReturn ,
124+ > ( {
109125 target,
110126 selector,
111127 detector,
112128} : {
113- target : Options [ "target" ] ;
129+ target : Options < Result , QuerySelectorResult > [ "target" ] ;
114130 selector : string ;
115- detector : Options [ "detector" ] ;
116- } ) : Promise < { element : QuerySelectorResult ; isDetected : boolean } > {
117- const element = target . querySelector ( selector ) ;
131+ detector : Options < Result , QuerySelectorResult > [ "detector" ] ;
132+ } ) : Promise < DetectorResultType < Result > > {
133+ const element = target . querySelector ( selector ) as QuerySelectorResult ;
118134
119- return { element , isDetected : await detector ( { element } ) } ;
135+ return await detector ( element ) ;
120136}
121137
122- export const waitElement = createWaitElement ( ) ;
138+ export const waitElement = createWaitElement ( {
139+ defaultOptions : getDefaultOptions ( ) ,
140+ } ) ;
141+
142+ export { getDefaultOptions } ;
0 commit comments