PuppeteerのElementHandleに対してjQueryのclosestのようなこと(祖先要素のうち、指定したセレクタにマッチする一番近いのを取得する)をしたかったのだけど、そんなメソッドは用意されていないようだったので、拡張することにした。
が、TypeScriptで書いているので、型定義もどうにかしないといけないということで、試行錯誤してどうにか目的を達成したようなので、その成果だけシェアしておこうと思う。
import { ElementHandle } from 'puppeteer/lib/cjs/puppeteer/common/JSHandle';
declare module 'puppeteer' {
interface ElementHandle<ElementType extends Element = Element> extends JSHandle {
closest(sel: string): Promise<ElementHandle | null>
}
}
declare module 'puppeteer/lib/cjs/puppeteer/common/JSHandle' {
interface ElementHandle extends JSHandle {
closest(sel: string): Promise<ElementHandle | null>
}
}
ElementHandle.prototype.closest = async function(sel: string): Promise<ElementHandle | null> {
const find = async function(e: ElementHandle, sel: string): Promise<ElementHandle | null> {
const parent = await e.$x('..').then(elems => elems.length > 0 ? elems[0] : null)
if (parent == null) {
return null
} else if (await parent.evaluate((node, sel) => node.matches(sel), sel)) {
return parent
} else {
return find(parent, sel)
}
}
return find(this, sel)
}
メソッドの型情報を2ヶ所に書かないといけないのはどうにかならないものだろうか。