elz*_*zoy 5 decorator typescript
假设我有一个A装饰器应用于返回字符串的方法。装饰器使用该字符串并最终返回B类型(一个类)。
class B {
constructor(text: string) { ... }
method() {...}
}
class X {
@A
someMethod(): string {
return 'lalala';
}
}
Run Code Online (Sandbox Code Playgroud)
装饰者
function A(target, property, descriptor) {
const text: string = descriptor.value();
descriptor.value = () => new B(text);
}
Run Code Online (Sandbox Code Playgroud)
发生了什么?现在someMethod返回一个B对象而不是字符串。但我不能做这样的事情:
class X {
constructor() {
this.someMethod().method();
}
@A
someMethod(): string {
return 'lala';
}
}
Run Code Online (Sandbox Code Playgroud)
为什么?因为someMethod从定义中是字符串类型,但装饰器使其返回B类型。我可以以某种方式让打字稿知道someMethod实际上返回B,而不是string?
3.0解决方案见下文
装饰器不能改变类型的结构,任何类型的装饰器都不能做到这一点(类、方法或参数装饰器)
使用 Typescript 2.8,您可以编写一个函数,该函数将另一个函数作为参数并执行返回类型的更改,但您将丢失参数名称、可选参数和多重签名等内容。您还应该小心,因为这样做会导致为someMethod字段分配方法,而不是类方法。因此,该字段必须在每个构造函数中分配,而不是分配给一次prototype,这可能会对性能产生影响。
class B<T> {
constructor(public value: T) { }
method() { return this.value; }
}
function A<T extends (...args: any[]) => any>(fn: T): ReplaceReturnType<T, B<ReturnType<T>>> {
return function (this: any, ...args: any[]) {
return new B<ReturnType<T>>(fn.apply(this, args));
} as any;
}
class X {
constructor() {
this.someMethod().method();
}
other() {}
someMethod = A(function (this: X): string {
this.other(); // We can access other members because of the explicit this parameter
return 'lala';
});
}
type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
type ReplaceReturnType<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) => TNewReturn :
IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => TNewReturn :
IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => TNewReturn :
IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => TNewReturn :
IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => TNewReturn :
IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => TNewReturn :
IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => TNewReturn :
IsValidArg<C> extends true ? (a: A, b: B, c: C) => TNewReturn :
IsValidArg<B> extends true ? (a: A, b: B) => TNewReturn :
IsValidArg<A> extends true ? (a: A) => TNewReturn :
() => TNewReturn
) : never
Run Code Online (Sandbox Code Playgroud)
编辑
由于最初的问题已得到解答,打字稿改进了该问题的可能解决方案。通过在剩余参数和扩展表达式中添加元组,我们现在不需要拥有以下所有重载ReplaceReturnType:
type ArgumentTypes<T> = T extends (... args: infer U ) => infer R ? U: never;
type ReplaceReturnType<T, TNewReturn> = (...a: ArgumentTypes<T>) => TNewReturn;
Run Code Online (Sandbox Code Playgroud)
这不仅更短,而且解决了许多问题
样本:
type WithOptional = ReplaceReturnType<(n?: number)=> string, Promise<string>>;
let x!: WithOptional; // Typed as (n?: number) => Promise<string>
x() // Valid
x(1); //Ok
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4849 次 |
| 最近记录: |