2017-07-31 77 views
2

我不明白爲什麼需要打字原稿明確泛型類型定義爲Child2Child3在這種情況下:打字稿:未能解決通用類裝飾的簽名

abstract class Base { 
    public static A: string = "Fallback_A"; 
    public DoSmthWithClassName(): string { 
     return "Fallback_DoSmth"; 
    } 

    constructor(...args: any[]); // overload for type consistency with children 
    constructor(x: string) 
    { } 
} 

// typeof any non-abstract child of Base 
type BaseType = typeof Base & (new(...args: any[]) => Base); 

// decorator, modifies methods and static properties 
function ClassDecorator<T extends BaseType>(valueA: string): (value: T) => T { 
    return (value: T) => { 
     value.prototype.DoSmthWithClassName =() => value.name + ".DoSmth." + value.A; 
     value.A = value.name + valueA; 
     return value; 
    } 
} 

@ClassDecorator("Foo") // OK 
class Child0 extends Base { 

} 

@ClassDecorator("Foo") // OK 
class Child1 extends Base { 
    constructor(x: number) { 
     super(x.toString()); 
    } 
} 

@ClassDecorator("Foo") // Unable to resolve... 
class Child2 extends Base { 
    static X: number = 0; 
} 

@ClassDecorator<typeof Child3>("Foo") // OK 
class Child3 extends Base { 
    static X: number = 0; 
} 
+0

如果裝飾器的返回類型改爲void,那麼該代碼片段運行時沒有錯誤,但編譯器在每種情況下仍然會將泛型類型解析爲BaseType,而我不明白爲什麼。 –

回答

1

的問題是,TS不能推斷T的類型來自唯一參數valueA。你想要的是在內部/恢復功能的通用參數:

// decorator, modifies methods and static properties 
function ClassDecorator(valueA: string) { 
    return function <T extends BaseType>(value: T): T { 
     value.prototype.DoSmthWithClassName =() => value.name + ".DoSmth." + value.A; 
     value.A = value.name + valueA; 
     return value; 
    } 
} 

你的版本是不導致與Child0和Child1任何問題,因爲它們在結構上相同的基礎。

+0

我沒有想到你的想法,但我決定放棄泛型並使用這種裝飾器: 'function ClassDecorator(valueA:string):(value:typeof Base)=> void'因爲編譯器假定'value.prototype.DoSmthWithClassName'在一般情況下,類型是'any'。 –