Typescript 增加函数的类型签名';如果当前参数是函数且该函数具有属性,则为s参数
接受一个更好的标题的建议,代替这个,我正在概述我的确切用例 我正在编写一个库,它允许远程执行方法和访问序列化边界(如Web Worker)后面的属性 一般流程是通过一个属性/值“句柄”遍历源对象、函数和数组的形状,该句柄表示为Typescript 增加函数的类型签名';如果当前参数是函数且该函数具有属性,则为s参数,typescript,Typescript,接受一个更好的标题的建议,代替这个,我正在概述我的确切用例 我正在编写一个库,它允许远程执行方法和访问序列化边界(如Web Worker)后面的属性 一般流程是通过一个属性/值“句柄”遍历源对象、函数和数组的形状,该句柄表示为IHandle接口 export interface IHandle<T> { property<K extends keyof T | ((...args: any) => any)>(key: K): K extends keyof T
IHandle
接口
export interface IHandle<T> {
property<K extends keyof T | ((...args: any) => any)>(key: K): K extends keyof T ? IHandle<T[K]> : any;
exec(
...args: T extends (...args: any) => any ? Parameters<T> : any
): T extends (...args: any) => any ? Promise<IHandle<ReturnType<T>>> : any;
value(): T extends (...args: any) => any ? any : Promise<T>;
dispose(): Promise<void>;
}
函数也可以传递基本属性
type Source = (foo: string) => foo
declare const handle: IHandle<Source>
const fooHandle: IHandle<string> = await handle.exec('foo')
const foo: string = await fooHandle.value()
我想看到的是:
const foo = await handle.exec(async (fooHandle: IHandle<string>) => {
const foo = await fooHandle.value()
})
最后,有条件地了解exec
param类型是否为回调,并根据需要对其进行更改
type Source = (one: string, cb: (prop: string) => any) => cb('foo')
declare const handle: IHandle<Source>
// Right now, fooHandle is a type string
const foo = await handle.exec('one', (fooHandle: IHandle<string>) => {
//...
})
type Source=(一:字符串,cb:(prop:string)=>any)=>cb('foo'))
声明常量句柄:IHandle
//现在,foodhandle是一个类型字符串
const foo=await handle.exec('one',(foodhandle:IHandle)=>{
//...
})
我不知道我是否100%理解您的用例,尤其是当涉及到如何处理回调的返回类型时。。。现在我假设它保持不变。此外,我还感到困惑的是,
IHandle
即使在T
与函数不同的情况下也会得到一个exec()
方法。也就是说,如果有人接受IHandle
并调用exec()
方法,或者调用可能发生的任何其他边缘情况,我真的不知道您打算怎么做。既然你没有明确地询问这个问题,并且你的示例代码不测试这个问题,那么我将在以下问题的范围之外考虑这些问题。
我在这里的方法是编写一个类型别名
HandlifyParams
,它将非回调类型T
单独保留,但将回调类型T
转换为一个新的回调类型,其参数都封装在IHandle
中,其返回类型单独保留(同样,不确定这是否是您想要的):
对于类型T
如(x:string,y:number)=>boolean
,编译器将使exec(x:string,y:number)=>Promise
,因为Handlify
和Handlify
分别是string
和number
。但是对于一个类型T
,比如(x:string,f:(x:string)=>number)=>boolean
,编译器将使exec(x:string,f:(x:IHandle)=>number)=>Promise
,因为Handlify number>
将修改其输入成为(x:IHandle)=>number
您可以验证示例测试现在编译时没有错误。万岁
我想我需要
推断
返回类型扩展了函数?我很难理解这一点。你能在打字游戏场上制作一个最小的可复制的例子吗?是的,对不起-我正在努力表达这个问题。我在示例底部添加了一个链接。谢谢,这很有帮助。但它似乎仍然不完整。createHandle()
有什么作用?它只是IHandle
的工厂函数。在上面的示例中,它基于其上方的源对象创建句柄。我将把这个问题改为使用与游乐场相同的语法,因为它更清晰,这正是我所需要的!我试图使用keyof
语法,并用Ihandle
包装键,但是我无法将其指定为回调类型的…args
。谢谢你。您的代码示例还帮助我更好地理解了expert
type Source = (cb: (prop: string) => any) => cb('foo')
declare const handle: IHandle<Source>
const foo = await handle.exec(async (fooHandle: IHandle<string>) => {
const foo = await fooHandle.value()
})
/// fooHandle is the wrong type
const foo = await handle.exec(async (fooHandle: string) => {
// ...
})
type Source = (one: string, cb: (prop: string) => any) => cb('foo')
declare const handle: IHandle<Source>
// Right now, fooHandle is a type string
const foo = await handle.exec('one', (fooHandle: IHandle<string>) => {
//...
})
type HandlifyParams<T> = T extends (...args: infer A) => infer R ?
(...args: { [I in keyof A]: IHandle<A[I]> }) => R : T;
export interface IHandle<T> {
exec(
...args: (T extends (...args: infer A) => any ? {
[I in keyof A]: HandlifyParams<A[I]>
} : never)
): T extends (...args: any) => any ? Promise<IHandle<ReturnType<T>>> : any;
}