打字稿类新评估PARAMS(Typescript new class by evaluate par

2019-09-29 08:51发布

class A {
   public aCall(a: any, payload: string) {}
   public bCall(a: any, payload: number) {}
   public cCall(a: any) {}
   .
   .
   .
}

function createNewClass(aCtor: A) {
  // load all of the A method and remove first params
  // generic code on here
  // Final result should be like this
  return class B {
    public aCall(payload: string) {}
    public bCall(payload: number) {}
  }
}

// C.d.ts
interface C extends createNewClass(A) {}

我能有一个函数(或装饰机上的方法)来评估新来的学员,并删除所有第一PARAMS产生新的类,这样我可以使用新的类用于扩展或者它只是不能做

Answer 1:

请参阅下面的3.0答案

您可以使用类似的方法来这个答案 。 您将需要更换的构造函数的返回类型,使用映射类型来创建忽略第一个参数的新功能:

type RemoveFirstArg<TCtor extends new (... args: any[]) => any > = ReplaceInstanceType<TCtor,  { [P in keyof InstanceType<TCtor>]: RemoveArg<InstanceType<TCtor>[P]> }>
function createNewClass<TCtor extends new (... args: any[]) => any >(aCtor: TCtor) : RemoveFirstArg<TCtor>{
    // load all of the A method and remove first params
    return null as any;
}

type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type RemoveArg<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 ? (b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => R :
    IsValidArg<I> extends true ? (b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => R :
    IsValidArg<H> extends true ? (b: B, c: C, d: D, e: E, f: F, g: G, h: H) => R :
    IsValidArg<G> extends true ? (b: B, c: C, d: D, e: E, f: F, g: G) => R :
    IsValidArg<F> extends true ? (b: B, c: C, d: D, e: E, f: F) => R :
    IsValidArg<E> extends true ? (b: B, c: C, d: D, e: E) => R :
    IsValidArg<D> extends true ? (b: B, c: C, d: D) => R :
    IsValidArg<C> extends true ? (b: B, c: C) => R :
    IsValidArg<B> extends true ? (b: B) => R :
    IsValidArg<A> extends true ? () => R :
    T
) : never

type ReplaceInstanceType<T, TNewReturn> = T extends new (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 ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => TNewReturn :
    IsValidArg<I> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => TNewReturn :
    IsValidArg<H> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => TNewReturn :
    IsValidArg<G> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => TNewReturn :
    IsValidArg<F> extends true ? new (a: A, b: B, c: C, d: D, e: E, f: F) => TNewReturn :
    IsValidArg<E> extends true ? new (a: A, b: B, c: C, d: D, e: E) => TNewReturn :
    IsValidArg<D> extends true ? new (a: A, b: B, c: C, d: D) => TNewReturn :
    IsValidArg<C> extends true ? new (a: A, b: B, c: C) => TNewReturn :
    IsValidArg<B> extends true ? new (a: A, b: B) => TNewReturn :
    IsValidArg<A> extends true ? new (a: A) => TNewReturn :
    new () => TNewReturn
) : never

//Usage
class A {
    public aCall(a: any, payload: string) { }
    public bCall(a: any, payload: number) { }
}

// Extending a class
class C extends createNewClass(A) { }

new C().aCall('xxx')

//For interfaces we can just use the type
interface IC extends RemoveFirstArg<typeof A> { }

注意的原因很多,许多类似的线是我们需要重新映射每个构造函数/函数的参数的具体数量。 上述实施适用于10个参数,这应该是足够的,但更可以增加。

编辑

由于原来的问题得到回答打字稿提高了可能的解决这个问题。 由于增加了在其他参数元组和蔓延表达我们现在并不需要对所有重载RemoveArgReplaceInstanceType

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

type ArgumentTypes<T> = T extends (... args: infer U ) => any ? U: never;
type ReplaceInstanceType<T, TNewInstance> = T extends new (...args: any[])=> infer R ? new (...a: ArgumentTypes<T>) => TNewInstance : never;

type ArgumentTypesSkipOne<T> = T extends (a: any, ... args: infer U ) => any ? U: never;
type RemoveArg<T> = T extends (a: any, ...args: any[])=> infer R ? (...a: ArgumentTypesSkipOne<T>) => R : T;

type RemoveFirstArg<TCtor extends new (... args: any[]) => any > = ReplaceInstanceType<TCtor,  { [P in keyof InstanceType<TCtor>]: RemoveArg<InstanceType<TCtor>[P]> }>

function createNewClass<TCtor extends new (... args: any[]) => any >(aCtor: TCtor) : RemoveFirstArg<TCtor>{
    // load all of the A method and remove first params
    return null as any;
}

这不仅是短,但它解决了不少问题

  • 可选参数保持可选
  • 参数名被保留
  • 适用于任何数量的参数


Answer 2:

如果由于某种原因,你所关心的实际上是试图实现这个东西,你可以不喜欢以下。 请注意,我只打算用两个参数来替代方法。 如果您需要做的所有方法,打字就必须在@ TitianCernicova-德拉戈米尔的回答更复杂的:

type RemoveFirstArgOfTwoArgMethods<T> = { [K in keyof T]:
  T[K] extends (a: any, payload: infer P) => infer R ? (payload: P) => R : T[K];
}

function createNewClass<T>(aCtor: new (...args: any[]) => T): new (...args: any[]) => RemoveFirstArgOfTwoArgMethods<T> {

  const B = (class extends (aCtor as any) {}) as new (...args: any[]) => RemoveFirstArgOfTwoArgMethods<T>;

  // you will need to actually decide what that first argument will be
  const firstVal: any = "whoKnows";

  Object.keys(aCtor.prototype).forEach(k => {
    const protoVal = (aCtor.prototype)[k];
    if ((typeof protoVal === 'function') && (protoVal.length === 2)) {
      B.prototype[k] = function (...args: any[]) { return (protoVal as Function).call(this, firstVal, ...args) }
    }
  })

  return B;
}

我们的想法是,它会延续原来的类,但代替它与调用以恒定的第一个参数原来的方法新的单参数的方法两个参数的方法(在这种情况下,它的字符串"whoKnows"但你可能想别的东西) 。

您可以验证上面的工作:

class A {
  public aCall(a: any, payload: string) {
    console.log("aCall(" + a + "," + payload + ")");
  }
}

const a = new A();
a.aCall("explicit", "call"); // aCall(explicit, call);

const C = createNewClass(A);
const c = new C();
c.aCall("implicit"); // aCall(whoKnows, implicit);

可能有警告的种种,当谈到玩游戏像这样的课,所以一定要小心,你真正了解你的使用情况,并会发生什么,当面对行为不符合它。

希望帮助。 祝好运!



文章来源: Typescript new class by evaluate params