См. Ниже для решения 3.0
Вы можете использовать аналогичный подход к ответу типа замены возврата здесь
type TProxyify<T> = {
[K in keyof T]: AddReturnType<T[K], string>;
};
type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type AddReturnType<T, TNewReturn> = 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) => R | TNewReturn :
IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => R | TNewReturn :
IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => R | TNewReturn :
IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => R | TNewReturn :
IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => R | TNewReturn :
IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => R | TNewReturn :
IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => R | TNewReturn :
IsValidArg<C> extends true ? (a: A, b: B, c: C) => R | TNewReturn :
IsValidArg<B> extends true ? (a: A, b: B) => R | TNewReturn :
IsValidArg<A> extends true ? (a: A) => R | TNewReturn :
() => R | TNewReturn
) : T
export function wrapType<T>(): TProxyify<T> {
return 1 as any;
}
interface IBaseInterface {
test(a?: boolean, b?: number): Promise<boolean>;
anotherTest?(a?: number): Promise<number>;
}
const s = wrapType<IBaseInterface>();
let ss = s.test(undefined, undefined); // will be string | Promise<boolean>
Проблема этого подхода заключается в том, что при использовании с дополнительными параметрами необязательный параметр становится обязательным (и имеет тип A | undefined). Вот почему вызов теста s.test(undefined, undefined);
, а не s.test();
Также не сохраняются имена параметров, что может быть проблемой для удобства чтения.
Редактировать
Поскольку первоначальный вопрос был дан, машинопись улучшила возможное решение этой проблемы. С добавлением кортежей в параметрах отдыха и выражениях нам теперь не нужно иметь все перегрузки:
type TProxyify<T> = {
[K in keyof T]: AddReturnType<T[K], string>;
};
type ArgumentTypes<T> = T extends (... args: infer U ) => any ? U: never;
type AddReturnType<T, TNewReturn> = T extends (...args: any[])=> infer R ? (...a: ArgumentTypes<T>) => TNewReturn | R : T;
export function wrapType<T>(): TProxyify<T> {
return 1 as any;
}
interface IBaseInterface {
test(a?: boolean, b?: number): Promise<boolean>;
anotherTest?(a?: number): Promise<number>;
}
const s = wrapType<IBaseInterface>();
let ss = s.test(undefined, undefined); // will be string | Promise<boolean>
Это не только короче, но и решает ряд проблем
- Необязательные параметры остаются необязательными
- Имена аргументов сохраняются
- Работает для любого количества аргументов