【问题标题】:Convert function signature type and keep generics转换函数签名类型并保留泛型
【发布时间】:2022-07-21 18:48:26
【问题描述】:

实际上,我不确定要搜索什么,所以也许问题已经在某个地方得到了回答,但是经过 2 天的测试和研究,我无法得到它......

我正在创建一个代理,它会调用后端,并且具有后端的类型。问题是同步方法会变成异步,所以我尝试通过将函数签名(有点“promisify”)从同步更改为异步来确保客户端的类型安全。对于常规函数,一切正常,但是当我谈到泛型时,我在签名中松散了泛型类型,这变成了未知...

我不确定即使使用最新的 TS 版本(目前是 4.7.3)也有办法做到这一点,但也许 TS 类型向导有解决方案?

目标是得到

const syncIdentity = <T>(o: T) => o;
// type is <T>(o:T) => T
const asyncIdentity = async <T>(o: T) => o;
// type is <T>(o:T) => Promise<T>

type PromisifiedSyncIdentity = Promisify<typeof syncIdentity>;
// want <T>(o:T) => Promise<T>
type PromisifiedAsyncIdentity = Promisify<typeof asyncIdentity>;
// want <T>(o:T) => Promise<T>

我的第一次尝试是这样的:

type Promisify<F extends (...args: any[]) => any> = (...args: Parameters<F>) => Promise<Awaited<ReturnType<F>>>;

type PromisifiedSyncIdentity = Promisify<typeof syncIdentity>;
// want <T>(o:T) => Promise<T>
// got (o:unknown) => Promise<unknown> :-/
type PromisifiedAsyncIdentity = Promisify<typeof asyncIdentity>;
// want <T>(o:T) => Promise<T>
// got (o:unknown) => Promise<unknown> :-/

当函数已经异步时,第二次尝试保持泛型(实际上,保持原始类型)

type Promisify<F extends (...args: any[]) => any> = F extends (...args: any[]) => infer R
    ? R extends Promise<any>
        ? F
        : (...args: Parameters<F>) => Promise<ReturnType<F>>
    : never;

type PromisifiedSyncIdentity = Promisify<typeof syncIdentity>;
// want <T>(o:T) => Promise<T>
// got (o:unknown) => Promise<unknown> :-/
type PromisifiedAsyncIdentity = Promisify<typeof asyncIdentity>;
// want <T>(o:T) => Promise<T>
// got <T>(o:T) => Promise<T> (YEAH! :-D)

就是这样!更改函数签名时,我找不到任何方法来保留泛型... 任何有才华的 TS 编码员都会对此有解决方案吗?或者可以肯定地告诉我这是不可能的吗?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    您已接近映射类型方法,您只需要有条件地将返回值包装在一个承诺中:

    type Promisify<FuncType extends (...args: any[]) => any> =
        // This condition will always be true, it's purely to introduce
        // the mapping and infer the types
        FuncType extends (...args: infer ArgTypes) => infer RetType
        ? RetType extends Promise<any>
            // It already returns a promise
            ? FuncType
            // It doesn't return a promise, wrap the return type in a promise
            : (...args: ArgTypes) => Promise<RetType>
        // This will never happen, because of our type constraint
        : never;
    

    然后你用类型参数定义你的类型:

    type PromisifiedSyncIdentity<T> = Promisify<typeof syncIdentity<T>>;
    //   ^?
    // want <T>(o:T) => Promise<T>
    type PromisifiedAsyncIdentity<T> = Promisify<typeof asyncIdentity<T>>;
    //   ^?
    // want <T>(o:T) => Promise<T>
    

    然后,例如,您可以像这样测试它:

    const f: PromisifiedSyncIdentity<string> = async (o: string) => o; // Works!
    

    Playground link

    【讨论】:

      猜你喜欢
      • 2021-06-12
      • 2021-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-12
      相关资源
      最近更新 更多