Skip to content

Commit

Permalink
fix(types): allow explicit subtypes for unwrapped handles (#1747)
Browse files Browse the repository at this point in the history
  • Loading branch information
dgozman authored Apr 11, 2020
1 parent 383332c commit cd2ecb2
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 23 deletions.
32 changes: 16 additions & 16 deletions utils/generate_types/overrides.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ export interface Page {
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>;
$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>;
$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, void, R>, arg?: any): Promise<R>;
$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>;

$$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>;
$$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>;
$$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], void, R>, arg?: any): Promise<R>;
$$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], void, R>, arg?: any): Promise<R>;

waitForFunction<R, Arg>(pageFunction: PageFunction<Arg, R>, arg: Arg, options?: PageWaitForFunctionOptions): Promise<SmartHandle<R>>;
waitForFunction<R>(pageFunction: PageFunction<void, R>, arg?: any, options?: PageWaitForFunctionOptions): Promise<SmartHandle<R>>;
Expand All @@ -88,14 +88,14 @@ export interface Frame {
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>;
$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>;
$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, void, R>, arg?: any): Promise<R>;
$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>;

$$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>;
$$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>;
$$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], void, R>, arg?: any): Promise<R>;
$$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], void, R>, arg?: any): Promise<R>;

waitForFunction<R, Arg>(pageFunction: PageFunction<Arg, R>, arg: Arg, options?: PageWaitForFunctionOptions): Promise<SmartHandle<R>>;
waitForFunction<R>(pageFunction: PageFunction<void, R>, arg?: any, options?: PageWaitForFunctionOptions): Promise<SmartHandle<R>>;
Expand All @@ -115,11 +115,11 @@ export interface Worker {
}

export interface JSHandle<T = any> {
evaluate<R, Arg>(pageFunction: PageFunctionOn<T, Arg, R>, arg: Arg): Promise<R>;
evaluate<R>(pageFunction: PageFunctionOn<T, void, R>, arg?: any): Promise<R>;
evaluate<R, Arg, O extends T = T>(pageFunction: PageFunctionOn<O, Arg, R>, arg: Arg): Promise<R>;
evaluate<R, O extends T = T>(pageFunction: PageFunctionOn<O, void, R>, arg?: any): Promise<R>;

evaluateHandle<R, Arg>(pageFunction: PageFunctionOn<T, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
evaluateHandle<R>(pageFunction: PageFunctionOn<T, void, R>, arg?: any): Promise<SmartHandle<R>>;
evaluateHandle<R, Arg, O extends T = T>(pageFunction: PageFunctionOn<O, Arg, R>, arg: Arg): Promise<SmartHandle<R>>;
evaluateHandle<R, O extends T = T>(pageFunction: PageFunctionOn<O, void, R>, arg?: any): Promise<SmartHandle<R>>;

jsonValue(): Promise<T>;
asElement(): T extends Node ? ElementHandle<T> : null;
Expand All @@ -133,14 +133,14 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
$$(selector: string): Promise<HTMLOrSVGElementHandle[]>;

$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, Arg, R>, arg: Arg): Promise<R>;
$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, Arg, R>, arg: Arg): Promise<R>;
$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K], void, R>, arg?: any): Promise<R>;
$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement, void, R>, arg?: any): Promise<R>;
$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E, void, R>, arg?: any): Promise<R>;

$$eval<K extends keyof HTMLElementTagNameMap, R, Arg>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], Arg, R>, arg: Arg): Promise<R>;
$$eval<R, Arg, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], Arg, R>, arg: Arg): Promise<R>;
$$eval<K extends keyof HTMLElementTagNameMap, R>(selector: K, pageFunction: PageFunctionOn<HTMLElementTagNameMap[K][], void, R>, arg?: any): Promise<R>;
$$eval<R>(selector: string, pageFunction: PageFunctionOn<HTMLOrSVGElement[], void, R>, arg?: any): Promise<R>;
$$eval<R, E extends HTMLOrSVGElement = HTMLOrSVGElement>(selector: string, pageFunction: PageFunctionOn<E[], void, R>, arg?: any): Promise<R>;
}

export interface BrowserType<Browser> {
Expand Down
120 changes: 113 additions & 7 deletions utils/generate_types/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,57 @@ playwright.chromium.launch().then(async browser => {
console.log(elements.map(x => x)[0].textContent);
return elements[3].innerHTML;
});
{
const value = await page.$eval('input', i => i.disabled);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const value = await page.$$eval('input', i => i[0].defaultValue);
const assertion: AssertType<string, typeof value> = true;
const frame = page.frames()[0];
const handle = await page.evaluateHandle(() => document.body);
for (const object of [frame, handle, page]) {
{
const value = await object.$eval('*[foo=bar]', i => i.textContent);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$eval('input', i => i.disabled);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const value = await object.$eval('input[foo=bar]', (i: HTMLInputElement) => i.disabled);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const value = await object.$eval('*[foo=bar]', (i, dummy) => i.textContent, 2);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$eval('input', (i, dummy) => i.disabled, 2);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const value = await object.$eval('input[foo=bar]', (i: HTMLInputElement, dummy: number) => i.disabled, 2);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const value = await object.$$eval('*[foo=bar]', i => i[0].textContent);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$$eval('input', i => i[0].defaultValue);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$$eval('input[foo=bar]', (i: HTMLInputElement[]) => i[0].defaultValue);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$$eval('*[foo=bar]', (i, dummy) => i[0].textContent, 2);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$$eval('input', (i, dummy) => i[0].defaultValue, 2);
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await object.$$eval('input[foo=bar]', (i: HTMLInputElement[], dummy: number) => i[0].defaultValue, 2);
const assertion: AssertType<string, typeof value> = true;
}
}
browser.close();
})();
Expand Down Expand Up @@ -343,7 +387,69 @@ playwright.chromium.launch().then(async browser => {
const value = await windowHandle.evaluate((x: Window, b) => b, 'world');
const assertion: AssertType<string, typeof value> = true;
}
{
const value = await page.evaluate(({a, b}) => b ? a : '123', { a: 3, b: true });
const assertion: AssertType<number | string, typeof value> = true;
}
{
const value = await page.evaluate(([a, b, c]) => ({a, b, c}), [3, '123', true]);
const assertion: AssertType<{a: string | number | boolean, b: string | number | boolean, c: string | number | boolean}, typeof value> = true;
}
{
const value = await page.evaluate(([a, b, c]) => ({a, b, c}), [3, '123', true] as const);
const assertion: AssertType<{a: 3, b: '123', c: true}, typeof value> = true;
}

{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluate(h => h[1].a);
const assertion: AssertType<string, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluate((h, p) => ({ a: h[1].a, p}), 123);
const assertion: AssertType<{a: string, p: number}, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluate((h: ({a: string, b: number})[]) => h[1].b);
const assertion: AssertType<number, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluate((h: ({a: string, b: number})[], prop) => h[1][prop], 'b' as const);
const assertion: AssertType<number, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluateHandle(h => h[1].a);
const assertion: AssertType<playwright.JSHandle<string>, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluateHandle((h, p) => ({ a: h[1].a, p}), 123);
const assertion: AssertType<playwright.JSHandle<{a: string, p: number}>, typeof value> = true;
}
{
const handle = await page.evaluateHandle(() => ([{a: '123'}]));
const value = await handle.evaluateHandle((h: ({a: string, b: number})[]) => h[1].b);
const assertion: AssertType<playwright.JSHandle<number>, typeof value> = true;
}
{
const handle = await page.waitForSelector('*');
const value = await handle.evaluate((e: HTMLInputElement) => e.disabled);
const assertion: AssertType<boolean, typeof value> = true;
}
{
const handle = await page.waitForSelector('*');
const value = await handle.evaluate((e: HTMLInputElement, x) => e.disabled || x, 123);
const assertion: AssertType<boolean | number, typeof value> = true;
}
{
const handle = await page.waitForSelector('*');
const value = await handle.evaluateHandle((e: HTMLInputElement, x) => e.disabled || x, 123);
const assertion: AssertType<playwright.JSHandle<boolean> | playwright.JSHandle<number>, typeof value> = true;
}

{
const handle = await page.evaluateHandle(() => 'hello');
Expand Down

0 comments on commit cd2ecb2

Please sign in to comment.