3.0 答案见下文
您可以使用与此answer 类似的方法。您将需要替换构造函数的返回类型,并使用映射类型来创建省略第一个参数的新函数:
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 个参数,应该足够了,但可以添加更多。
编辑
自从回答了最初的问题以来,打字稿已经改进了这个问题的可能解决方案。随着Tuples in rest parameters and spread expressions 的添加,我们现在不需要为RemoveArg 和ReplaceInstanceType 提供所有重载:
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;
}
这不仅更短,而且解决了许多问题
- 可选参数仍然是可选的
- 参数名称被保留
- 适用于任意数量的参数