在 Typescript 中,如何在存储然后从数组访问所述对象时维护对象类型?
In Typescript, how do I maintain an objects type when storing and then accessing said object from an array?
在打字稿中,我注意到当我将一个复杂的对象放入数组中时,当我尝试从数组中访问该对象时,它会丢失其类型,而只是变成对象类型。
例如
let myArray = return await this.browser.evaluate((sel: string) => Array.from(document.querySelectorAll(sel)), selector)
document.querySelectorAll(sel)
returns 一个 NodeList<Element>
即 ArrayLike
。 Array.from
应该将 NodeList
转换为元素数组,但是一旦形成数组,所有数组元素都会失去其 Element
类型
我有一个函数只接受 Element
类型的参数,但是当我尝试将 myArray[0]
作为参数传递给所述函数时,出现错误:Error: Unsupported target type: object
我已经尝试了很多不同的方法来尝试让数组保持其对象类型,以至于很难解释每一种方法。我想知道如何创建一个 Element
s 数组并让它们在以后访问时继续为 Element
s 而不是通用 object
s
这是我所做测试的更多背景信息
我要去这个页面:https://www.w3schools.com/html/html_tables.asp
我传递给评估的选择器是 table[id="customers"] tbody tr
这应该与出现在 table.
中的 6 行相匹配
let test = await this.browser.evaluate((sel: string) =>
Array.from(document.querySelectorAll(sel)), selector)
console.log('testy1: ', test)
console.log('testy2: ', test[0])
console.log('testy3: ', typeof(test[0]))
当我运行上面的代码时,这是我在控制台日志中得到的输出:
testy1: [ {}, {}, {}, {}, {}, {}, {} ]
testy2: {}
testy3: object
它似乎匹配从页面中抓取元素,因为它正确返回了 6 个元素。但也许问题是返回的对象是空的?我不确定。
我想我的问题可能与这个问题有关:
但是这个问题的解决方案对我不起作用,因为 href 不是对象类型 Element
的 属性
这里的问题是您传递给 page.evaluate
的函数是 运行 在浏览器上下文中(在浏览器页面内)。要将结果从浏览器上下文发送到 Node.js 环境,结果会被序列化。
请参阅 page.evaluate
文档中的 return 类型:
returns: Promise<Serializable> Promise which resolves to the return value of pageFunction
这里的Serializable
表示你的数据会通过JSON.stringify
传递到Node.js环境,那里会自动为你解析。但是,此过程将删除对象的所有 non-serializable 属性。这就是您最终得到许多空对象的原因。
在 puppeteer 中获取元素句柄
要获取页面上元素的句柄,您需要使用 page.$
, which creates an object (in your Node.js environment) that is linked to an element inside the browser context. These kind of handles can also be passed to page.evaluate
calls. To query for multiple element, you can use the function page.$$
。
代码示例
这是一个示例,它首先查询一个元素,然后将元素句柄传递给评估函数以读取属性。
const elementHandle = await page.$('a');
const result = await page.evaluate(el => el.href, elementHandle);
TypeScript 的使用
关于 TypeScript 的问题是,TypeScript 在这种情况下无法正确预测类型。对于 TypeScript 编译器,这看起来像是一个普通的函数调用,而实际上,该函数被发送到客户端以供执行。因此,在这种情况下你必须自己转换类型,否则 Typescript 只会假设 any
作为参数类型:
const elementHandle = await page.$('a');
const result = await page.evaluate((el: { href: string }) => el.href, elementHandle);
我在类型定义方面遇到了同样的问题,并且元素未从任何库中导出。
为了使用 el 方法获得适当的智能感知,我使用以下示例更改了我的代码:
发件人:
...
await page.waitForTimeout(3000)
await page.waitForSelector('button[type=submit]')
await page.$eval('button[type=submit]', el => el.click())
await page.waitForNavigation({waitUntil: "load"})
await page.goto(url)
...
为此:
...
await page.waitForTimeout(3000)
await page.waitForSelector('button[type=submit]')
await page.$('button[type=submit]').then(el => {
el.click()
})
await page.waitForNavigation({waitUntil: "load"})
await page.goto(url)
...
puppeteer element intelisense example
PS:我在 DefinedType Github https://github.com/DefinitelyTyped/DefinitelyTyped/issues/24419
上的定义类型中发现了问题
在打字稿中,我注意到当我将一个复杂的对象放入数组中时,当我尝试从数组中访问该对象时,它会丢失其类型,而只是变成对象类型。
例如
let myArray = return await this.browser.evaluate((sel: string) => Array.from(document.querySelectorAll(sel)), selector)
document.querySelectorAll(sel)
returns 一个 NodeList<Element>
即 ArrayLike
。 Array.from
应该将 NodeList
转换为元素数组,但是一旦形成数组,所有数组元素都会失去其 Element
类型
我有一个函数只接受 Element
类型的参数,但是当我尝试将 myArray[0]
作为参数传递给所述函数时,出现错误:Error: Unsupported target type: object
我已经尝试了很多不同的方法来尝试让数组保持其对象类型,以至于很难解释每一种方法。我想知道如何创建一个 Element
s 数组并让它们在以后访问时继续为 Element
s 而不是通用 object
s
这是我所做测试的更多背景信息
我要去这个页面:https://www.w3schools.com/html/html_tables.asp
我传递给评估的选择器是 table[id="customers"] tbody tr
这应该与出现在 table.
let test = await this.browser.evaluate((sel: string) =>
Array.from(document.querySelectorAll(sel)), selector)
console.log('testy1: ', test)
console.log('testy2: ', test[0])
console.log('testy3: ', typeof(test[0]))
当我运行上面的代码时,这是我在控制台日志中得到的输出:
testy1: [ {}, {}, {}, {}, {}, {}, {} ]
testy2: {}
testy3: object
它似乎匹配从页面中抓取元素,因为它正确返回了 6 个元素。但也许问题是返回的对象是空的?我不确定。
我想我的问题可能与这个问题有关:
但是这个问题的解决方案对我不起作用,因为 href 不是对象类型 Element
这里的问题是您传递给 page.evaluate
的函数是 运行 在浏览器上下文中(在浏览器页面内)。要将结果从浏览器上下文发送到 Node.js 环境,结果会被序列化。
请参阅 page.evaluate
文档中的 return 类型:
returns: Promise<Serializable> Promise which resolves to the return value of
pageFunction
这里的Serializable
表示你的数据会通过JSON.stringify
传递到Node.js环境,那里会自动为你解析。但是,此过程将删除对象的所有 non-serializable 属性。这就是您最终得到许多空对象的原因。
在 puppeteer 中获取元素句柄
要获取页面上元素的句柄,您需要使用 page.$
, which creates an object (in your Node.js environment) that is linked to an element inside the browser context. These kind of handles can also be passed to page.evaluate
calls. To query for multiple element, you can use the function page.$$
。
代码示例
这是一个示例,它首先查询一个元素,然后将元素句柄传递给评估函数以读取属性。
const elementHandle = await page.$('a');
const result = await page.evaluate(el => el.href, elementHandle);
TypeScript 的使用
关于 TypeScript 的问题是,TypeScript 在这种情况下无法正确预测类型。对于 TypeScript 编译器,这看起来像是一个普通的函数调用,而实际上,该函数被发送到客户端以供执行。因此,在这种情况下你必须自己转换类型,否则 Typescript 只会假设 any
作为参数类型:
const elementHandle = await page.$('a');
const result = await page.evaluate((el: { href: string }) => el.href, elementHandle);
我在类型定义方面遇到了同样的问题,并且元素未从任何库中导出。
为了使用 el 方法获得适当的智能感知,我使用以下示例更改了我的代码:
发件人:
...
await page.waitForTimeout(3000)
await page.waitForSelector('button[type=submit]')
await page.$eval('button[type=submit]', el => el.click())
await page.waitForNavigation({waitUntil: "load"})
await page.goto(url)
...
为此:
...
await page.waitForTimeout(3000)
await page.waitForSelector('button[type=submit]')
await page.$('button[type=submit]').then(el => {
el.click()
})
await page.waitForNavigation({waitUntil: "load"})
await page.goto(url)
...
puppeteer element intelisense example
PS:我在 DefinedType Github https://github.com/DefinitelyTyped/DefinitelyTyped/issues/24419
上的定义类型中发现了问题