【问题标题】:how to remove properties and promisify method via mapped type in TypeScript如何通过 TypeScript 中的映射类型删除属性和 promisify 方法
【发布时间】:2018-08-31 10:02:39
【问题描述】:

这里是代码

class A {
    x = 0;
    y = 0;
    visible = false;
    render() {
        return 1;
    }
}

type RemoveProperties<T> = {
    readonly [P in keyof T]: T[P] extends Function ? T[P] : never//;
};

type JustMethodKeys<T> = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T];
type JustMethods<T> = Pick<T, JustMethodKeys<T>>;


type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;

type Promisified<T extends Function> =
    T extends (...args: any[]) => Promise<any> ? T : (
        T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
            IsValidArg<J> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<R> :
            IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<R> :
            IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<R> :
            IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<R> :
            IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<R> :
            IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => Promise<R> :
            IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => Promise<R> :
            IsValidArg<C> extends true ? (a: A, b: B, c: C) => Promise<R> :
            IsValidArg<B> extends true ? (a: A, b: B) => Promise<R> :
            IsValidArg<A> extends true ? (a: A) => Promise<R> :
            () => Promise<R>
        ) : never
    );



var a = new A() as JustMethods<A>  // I want to JustMethod && Promisified
a.visible // error
var b = a.render() // b should be Promise<number>

如何实现?我想去掉可见和promisify的渲染方法,如何合成Promisified和JustMethods?

如何实现?我想去掉可见和promisify的渲染方法,如何合成Promisified和JustMethods?

【问题讨论】:

    标签: typescript typescript-typings mapped-types


    【解决方案1】:

    与另一个答案类似,但这是我得出的结论

    type Method = (...args: any) => any;
    type KeysOfMethods<T> = ({ [P in keyof T]: T[P] extends Method ? P : never })[keyof T];
    type PickMethods<T> = Pick<T, KeysOfMethods<T>>;
    type Promisify<T> = T extends Promise<infer U> ? Promise<U> : Promise<T>;
    type PromisifyMethod<T extends Method> = (...args: Parameters<T>) => Promisify<ReturnType<T>>;
    type PromisifyMethods<T> = { [P in keyof T]: T[P] extends Method ? PromisifyMethod<T[P]> : T[P] };
    
    type PromisifiedMethodsOnly<T> = PickMethods<PromisifyMethods<T>>
    

    【讨论】:

      【解决方案2】:

      您需要使用映射类型,该类型仅采用使用 JustMethodKeys 的类型的方法,并在每个属性上使用 Promisified

      class A {
          x = 0;
          y = 0;
          visible = false;
          render() {
              return 1;
          }
      }
      
      type JustMethodKeys<T> = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T];
      
      type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
      
      type Promisified<T extends Function> =
          T extends (...args: any[]) => Promise<any> ? T : (
              T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
                  IsValidArg<J> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<R> :
                  IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<R> :
                  IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<R> :
                  IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<R> :
                  IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<R> :
                  IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => Promise<R> :
                  IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => Promise<R> :
                  IsValidArg<C> extends true ? (a: A, b: B, c: C) => Promise<R> :
                  IsValidArg<B> extends true ? (a: A, b: B) => Promise<R> :
                  IsValidArg<A> extends true ? (a: A) => Promise<R> :
                  () => Promise<R>
              ) : never
          );
      
      type PromisifyMethods<T> = { 
          // We take just the method key and Promisify them, 
          // We have to use T[P] & Function because the compiler will not realize T[P] will always be a function
          [P in JustMethodKeys<T>] : Promisified<T[P] & Function>
      }
      
      //Usage
      declare var a : PromisifyMethods<A>  
      a.visible // error
      var b = a.render() // b is Promise<number>
      

      编辑

      自从回答了原始问题以来,打字稿已经改进了该问题的可能解决方案。随着Tuples in rest parameters and spread expressions 的添加,我们现在不需要为Promisified 提供所有重载:

      type JustMethodKeys<T> = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T];
      
      
      type ArgumentTypes<T> = T extends (... args: infer U ) => any ? U: never;
      type Promisified<T> = T extends (...args: any[])=> infer R ? (...a: ArgumentTypes<T>) => Promise<R> : never;
      
      type PromisifyMethods<T> = { 
          // We take just the method key and Promisify them, 
          // We have to use T[P] & Function because the compiler will not realize T[P] will always be a function
          [P in JustMethodKeys<T>] : Promisified<T[P]>
      }
      
      //Usage
      declare var a : PromisifyMethods<A>  
      a.visible // error
      var b = a.render("") // b is Promise<number> , render is render: (k: string) => Promise<number>
      

      这不仅更短,而且解决了许多问题

      • 可选参数仍然是可选的
      • 参数名称被保留
      • 适用于任意数量的参数

      【讨论】:

      • @Florian 我认为这不是您要寻找的。听起来你想要的是装饰器。这个问题与更改类上的函数签名严格相关,它没有运行时行为。但是问一个问题,有人会回答它:-)
      猜你喜欢
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      • 2020-05-02
      • 2020-09-08
      相关资源
      最近更新 更多