We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在开发 Chrome 扩展程序的时候,大部分 chrome.* 接口都是类似于下面这样的 callback 风格:
chrome.tabs.create({ url: 'https://hcfy.app' }, tab => { console.log(tab.id) })
新出的 Manifest V3 同时支持 callback 风格与 Promise 风格:
// Manifest V3 中的 Promise 风格 const tab = await chrome.tabs.create({ url: 'https://hcfy.app' }) console.log(tab.id)
但划词翻译目前仍然停留在 Manifest V2,能且只能用 callback 写法,但我又想要用 Promise,怎么办?
几年前,我曾开发过一个项目叫 chrome-call,它通过如下方式使用:
import chromeCall from 'chrome-call' const tab = await chromeCall(chrome.tabs, 'create', { url: 'https://hcfy.app' })
现在,我更喜欢 Node.js 中 util.promisify() 的形式,而 chrome 版本的 promisify() 函数很快就写好了:
promisify()
function chromePromisify(fn) { return function (...args) { return new Promise((resolve, reject) => { fn.call(null, ...args, (result) => { const error = chrome.runtime.lastError if (error) { reject(error) } else { resolve(result) } }) }) } } const tabsCreate = chromePromisify(chrome.tabs.create) const tab = await tabsCreate({ url: 'https://hcfy.app' })
但是接下来,在给这个函数添加 TypeScript 类型注解的时候,我犯了难。
function chromePromisify(fn: (...args: any[]) => void) { return function (...args: any[]) { return new Promise((resolve, reject) => { fn.call(null, ...args, (result: unknown) => { const error = chrome.runtime.lastError if (error) { reject(error) } else { resolve(result) } }) }) } }
这样确实能用,但会丢掉 @types/chrome 里对 chrome.tabs.create 函数的类型提示:
chrome.tabs.create
// 直接使用时,TypeScript 能检测参数的类型 chrome.tabs.create({ url: 'https://hcfy.app' }, tab => { // 并且能推断出 tab 的类型是 chrome.Tabs.tab console.log(tab.id) }) // 用了 chromePromisify 之后 const tabsCreate = chromePromisify(chrome.tabs.create) // 参数是 any[] 所以填什么都不会报类型错,返回值类型是 unknow 所以必须自行声明类型 const tab: chrome.Tabs.tab = await tabsCreate({ url: 'https://hcfy.app' })
我希望这个函数能更加智能,所以参考了 @types/node 中对 util.promisify() 的类型注解,写出了第二个版本:
function chromePromisify<TResult>(fn: (callback: (result: TResult) => void) => void): () => Promise<TResult> function chromePromisify<T1, TResult>(fn: (arg1: T1, callback: (result: TResult) => void) => void): (arg1: T1) => Promise<TResult> // 后面就是不断增加 T1、T2、T3…… function chromePromisify(fn: Function): Function { return function (...args: any[]) { return new Promise((resolve, reject) => { fn.call(null, ...args, (result: unknown) => { const error = chrome.runtime.lastError if (error) { reject(error) } else { resolve(result) } }) }) } }
在用 chrome.tabs.create 方法做测试时,这个版本很好的达成了我的预期,点击此链接可以看到 TypeScript 成功在参数类型错误时报了错,且能正确推断出返回值的类型。
但是在实际使用中,我发现它对于有多个重载的函数不起作用,比如 chrome.windows.get,点击此链接可以看到具体情况。
chrome.windows.get
我想更进一步,让它支持有多个重载的函数。我猜测应该可以用 infer 关键字提取出函数的参数类型,于是搜了一下,然后就被密密麻麻的代码劝退了:https://stackoverflow.com/a/74209026
infer
不过我还是想优化一下第二个版本那种不断重复添加 T1、T2、T3 的写法。我想要的类型是最后一个参数是 callback 的函数,而我不想通过重复给它添加 T1、T2、T3 的重载来获取到正确的类型。
在经过一番搜索之后,我在这里查到了下面这种写法:
type Bar = any type Qux = number // 前面几个都是 Bar 类型,但最后一个是 Qux 的 tuple type WithLastQux = [...Bar[], Qux]
这种形式不正好能满足我想要的“最后一个参数是 callback 的函数”的类型吗:
type FnWithLastCallback = (...args: [...unknow[], (result: unknow) => void]) => void
上面这个类型可以再进一步,提取出参数列表与函数结果:
type FnWithLastCallback<TArgs extends Array<unknow>, TResult> = (...args: [...TArgs, (result: TResult) => void]) => void
然后,我们用这个类型来改造上面的 chromePromisify:
chromePromisify
function chromePromisify<TArgs extends Array<unknown>,TResult>(fn: (...args:[...TArgs, (result:TResult)=>void])=>void) { return function (...args: TArgs) { return new Promise<TResult>((resolve, reject) => { fn.call(null, ...args, (result: TResult) => { const error = chrome.runtime.lastError if (error) { reject(error) } else { resolve(result) } }) }) } }
这样,就不用重复声明 T1、T2、T3 类型了。点击这里查看
The text was updated successfully, but these errors were encountered:
hello,有个问题想请教您,方便联系您一下吗?
Sorry, something went wrong.
No branches or pull requests
背景
在开发 Chrome 扩展程序的时候,大部分 chrome.* 接口都是类似于下面这样的 callback 风格:
新出的 Manifest V3 同时支持 callback 风格与 Promise 风格:
但划词翻译目前仍然停留在 Manifest V2,能且只能用 callback 写法,但我又想要用 Promise,怎么办?
解决方案
几年前,我曾开发过一个项目叫 chrome-call,它通过如下方式使用:
现在,我更喜欢 Node.js 中 util.promisify() 的形式,而 chrome 版本的
promisify()
函数很快就写好了:但是接下来,在给这个函数添加 TypeScript 类型注解的时候,我犯了难。
第一个版本的类型注解
这样确实能用,但会丢掉 @types/chrome 里对
chrome.tabs.create
函数的类型提示:第二个版本的类型注解
我希望这个函数能更加智能,所以参考了 @types/node 中对 util.promisify() 的类型注解,写出了第二个版本:
在用
chrome.tabs.create
方法做测试时,这个版本很好的达成了我的预期,点击此链接可以看到 TypeScript 成功在参数类型错误时报了错,且能正确推断出返回值的类型。但是在实际使用中,我发现它对于有多个重载的函数不起作用,比如
chrome.windows.get
,点击此链接可以看到具体情况。第三个版本
我想更进一步,让它支持有多个重载的函数。我猜测应该可以用
infer
关键字提取出函数的参数类型,于是搜了一下,然后就被密密麻麻的代码劝退了:https://stackoverflow.com/a/74209026不过我还是想优化一下第二个版本那种不断重复添加 T1、T2、T3 的写法。我想要的类型是最后一个参数是 callback 的函数,而我不想通过重复给它添加 T1、T2、T3 的重载来获取到正确的类型。
在经过一番搜索之后,我在这里查到了下面这种写法:
这种形式不正好能满足我想要的“最后一个参数是 callback 的函数”的类型吗:
上面这个类型可以再进一步,提取出参数列表与函数结果:
然后,我们用这个类型来改造上面的
chromePromisify
:这样,就不用重复声明 T1、T2、T3 类型了。点击这里查看
The text was updated successfully, but these errors were encountered: