Skip to content

Commit

Permalink
chore: use nominal typing (#8630)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrandolf committed Jul 5, 2022
1 parent 332e507 commit 7a2c0f2
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 21 deletions.
39 changes: 36 additions & 3 deletions .eslintignore
@@ -1,6 +1,39 @@
assets/
## [START] Keep in sync with .gitignore
# Dependencies
node_modules

# Production
build/
coverage/
lib
lib/

# Generated files
tsconfig.tsbuildinfo
puppeteer.api.json
puppeteer*.tgz
yarn.lock
.docusaurus/
.cache-loader
.local-chromium/
.local-firefox/
test/output-*/
.dev_profile*
coverage/

# IDE Artifacts
.vscode

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
## [END] Keep in sync with .gitignore

# ESLint ignores.
assets/
vendor/
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -16,6 +16,7 @@ yarn.lock
.local-firefox/
test/output-*/
.dev_profile*
coverage/

# IDE Artifacts
.vscode
Expand Down
7 changes: 4 additions & 3 deletions .prettierignore
@@ -1,5 +1,4 @@
# Keep in sync with .gitignore

## [START] Keep in sync with .gitignore
# Dependencies
node_modules

Expand All @@ -18,6 +17,7 @@ yarn.lock
.local-firefox/
test/output-*/
.dev_profile*
coverage/

# IDE Artifacts
.vscode
Expand All @@ -32,6 +32,7 @@ test/output-*/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
## [END] Keep in sync with .gitignore

# Prettier-only ignores.
assets/
Expand All @@ -41,4 +42,4 @@ package.json
test/assets/
vendor/
docs/
versioned_*/
versioned_*/
15 changes: 15 additions & 0 deletions docs/api/puppeteer.jshandle.___jshandlesymbol_.md
@@ -0,0 +1,15 @@
---
sidebar_label: JSHandle.[__JSHandleSymbol]
---

# JSHandle.\[\_\_JSHandleSymbol\] property

Used for nominally typing [JSHandle](./puppeteer.jshandle.md).

**Signature:**

```typescript
class JSHandle {
[__JSHandleSymbol]?: T;
}
```
6 changes: 6 additions & 0 deletions docs/api/puppeteer.jshandle.md
Expand Up @@ -26,6 +26,12 @@ JSHandle prevents the referenced JavaScript object from being garbage-collected

JSHandle instances can be used as arguments for [Page.$eval()](./puppeteer.page._eval.md), [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).

## Properties

| Property | Modifiers | Type | Description |
| --------------------------------------------------------------------- | --------- | ---- | -------------------------------------------------------------------------------- |
| [\[\_\_JSHandleSymbol\]?](./puppeteer.jshandle.___jshandlesymbol_.md) | | T | <i>(Optional)</i> Used for nominally typing [JSHandle](./puppeteer.jshandle.md). |

## Methods

| Method | Modifiers | Description |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -28,7 +28,7 @@
},
"scripts": {
"test": "c8 --check-coverage --lines 94 run-s test:chrome test:chrome:* test:firefox",
"test:types": "tsc -b test-d",
"test:types": "tsd",
"test:install": "scripts/test-install.sh",
"test:firefox": "cross-env PUPPETEER_PRODUCT=firefox MOZ_WEBRENDER=0 mocha",
"test:chrome": "mocha",
Expand Down
4 changes: 2 additions & 2 deletions src/common/AriaQueryHandler.ts
Expand Up @@ -111,7 +111,7 @@ const waitFor = async (
return element;
},
};
return domWorld._waitForSelectorInPage(
return (await domWorld._waitForSelectorInPage(
(_: Element, selector: string) => {
return (
globalThis as any as unknown as {
Expand All @@ -122,7 +122,7 @@ const waitFor = async (
selector,
options,
binding
);
)) as ElementHandle<Element> | null;
};

const queryAll = async (
Expand Down
6 changes: 5 additions & 1 deletion src/common/DOMWorld.ts
Expand Up @@ -547,7 +547,11 @@ export class DOMWorld {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting');
return queryHandler.waitFor(this, updatedSelector, options);
return (await queryHandler.waitFor(
this,
updatedSelector,
options
)) as ElementHandle<NodeFor<Selector>> | null;
}

// If multiple waitFor are set up asynchronously, we need to wait for the
Expand Down
9 changes: 7 additions & 2 deletions src/common/ElementHandle.ts
Expand Up @@ -847,7 +847,10 @@ export class ElementHandle<
queryHandler.queryOne,
'Cannot handle queries for a single element with the given selector'
);
return queryHandler.queryOne(this, updatedSelector);
return (await queryHandler.queryOne(
this,
updatedSelector
)) as ElementHandle<NodeFor<Selector>> | null;
}

/**
Expand All @@ -870,7 +873,9 @@ export class ElementHandle<
queryHandler.queryAll,
'Cannot handle queries for a multiple element with the given selector'
);
return await queryHandler.queryAll(this, updatedSelector);
return (await queryHandler.queryAll(this, updatedSelector)) as Array<
ElementHandle<NodeFor<Selector>>
>;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/common/ExecutionContext.ts
Expand Up @@ -426,9 +426,9 @@ export class ExecutionContext {
/**
* @internal
*/
async _adoptElementHandle(
elementHandle: ElementHandle<Node>
): Promise<ElementHandle<Node>> {
async _adoptElementHandle<T extends ElementHandle<Node>>(
elementHandle: T
): Promise<T> {
assert(
elementHandle.executionContext() !== this,
'Cannot adopt handle that already belongs to this execution context'
Expand All @@ -437,6 +437,6 @@ export class ExecutionContext {
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId,
});
return this._adoptBackendNodeId(nodeInfo.node.backendNodeId);
return (await this._adoptBackendNodeId(nodeInfo.node.backendNodeId)) as T;
}
}
7 changes: 7 additions & 0 deletions src/common/JSHandle.ts
Expand Up @@ -23,6 +23,8 @@ import {MouseButton} from './Input.js';
import {releaseObject, valueFromRemoteObject, createJSHandle} from './util.js';
import type {ElementHandle} from './ElementHandle.js';

declare const __JSHandleSymbol: unique symbol;

/**
* @public
*/
Expand Down Expand Up @@ -68,6 +70,11 @@ export interface BoundingBox extends Point {
* @public
*/
export class JSHandle<T = unknown> {
/**
* Used for nominally typing {@link JSHandle}.
*/
[__JSHandleSymbol]?: T;

#client: CDPSession;
#disposed = false;
#context: ExecutionContext;
Expand Down
2 changes: 1 addition & 1 deletion test-d/ElementHandle.test-d.ts
Expand Up @@ -68,7 +68,7 @@ declare const handle: ElementHandle;
await handle.$eval(
'some-element',
(element, value) => {
expectType<Node>(element);
expectType<Element>(element);
return value;
},
1
Expand Down
8 changes: 4 additions & 4 deletions test-d/JSHandle.test-d.ts
@@ -1,4 +1,4 @@
import {expectAssignable, expectNotAssignable, expectType} from 'tsd';
import {expectNotAssignable, expectNotType, expectType} from 'tsd';
import {ElementHandle} from '../lib/esm/puppeteer/common/ElementHandle.js';
import {JSHandle} from '../lib/esm/puppeteer/common/JSHandle.js';

Expand Down Expand Up @@ -61,16 +61,16 @@ declare const handle2: JSHandle<{test: number}>;
{
{
expectType<JSHandle<number>>(await handle2.getProperty('test'));
expectNotAssignable<JSHandle<string>>(await handle2.getProperty('test'));
expectNotType<JSHandle<unknown>>(await handle2.getProperty('test'));
}
{
expectType<JSHandle<unknown>>(
await handle2.getProperty('key-doesnt-exist')
);
expectAssignable<JSHandle<string>>(
expectNotType<JSHandle<string>>(
await handle2.getProperty('key-doesnt-exist')
);
expectAssignable<JSHandle<number>>(
expectNotType<JSHandle<number>>(
await handle2.getProperty('key-doesnt-exist')
);
}
Expand Down

0 comments on commit 7a2c0f2

Please sign in to comment.