См. Ниже для ответа 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 аргументов, которых должно быть достаточно, но можно добавить еще.
Редактировать
Поскольку на первоначальный вопрос был дан ответ, машинопись улучшила возможное решение этой проблемы. С добавлением кортежей в параметрах отдыха и выражениях нам теперь не нужно иметь все перегрузки для 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;
}
Это не только короче, но и решает ряд проблем
- Необязательные параметры остаются необязательными
- Имена аргументов сохраняются
- Работает для любого количества аргументов