Working around loss of support for type constraint being self

前端 未结 3 627
野性不改
野性不改 2021-01-05 06:07

This is something I\'ve been doing in older versions of TypeScript and I use this method in C#, but it doesn\'t work in the latest 1.0 version of TypeScript.

Here\'s

相关标签:
3条回答
  • 2021-01-05 06:35

    I accepted Steve's answer because he suggested to use Base<T extends Base<any>>, but I wanted to keep a copy of the code change that fixed the problem on Stack Overflow:

    class Base<T extends Base<any>> { // 1. Set as any
        children: Array<T>;
    
        doAction() {
            this.children[0].promise();
        }
    
        promise(): T {
            return <any> this; // 2. cast to any
        }
    }
    
    class Child extends Base<Child> {
        public myString: string;
    }
    
    new Child().promise().myString;
    

    This requires a cast to any, but it's not so bad since it's only in the base class. This change doesn't affect anything using the Child or Base classes, so overall it was a very ideal alternative.


    Update: In TS 1.7+ this can be done using a polymorphic this:

    class Base {
        children: Array<this>;
    
        doAction() {
            this.children[0].promise();
        }
    
        promise(): this {
            return this;
        }
    }
    
    class Child extends Base {
        public myString: string;
    }
    
    new Child().promise().myString;
    
    0 讨论(0)
  • 2021-01-05 06:38

    You are no longer allowed to use T here:

    class Base<T extends Base<T>>
    --------------------------^
    

    You either have to make your class non-generic or use:

    class Base<T extends Base<any>>
    

    The reason given for this was to make the compiler simpler:

    In our continued efforts to simplify the language, we're simplifying what generic constraints can entail.

    The added overhead in terms of type-checking, error-reporting, and design complexity did not add enough additional expressiveness to make it worthwhile for 1.0. We may revisit this in future versions of TypeScript.

    -- Breaking Changes Wiki

    0 讨论(0)
  • 2021-01-05 06:41

    promise() : T { return this; } it is very weak assumption that can be easily broken, because downcasting defined in a base class just cannot work for any sub-class

    For example in you case, if anyone defines class SuperChild extends Child {} then promise() of SuperChild is going to give you Child instead of SuperChild.

    Besides that here is how you can make it work the way it used to:

    class Base<T> {
        public children : Array<T>;
    
        constructor(
            private toSelf: () => T,
            private toBase: (something: T) => Base<T>
        ) {
        }
    
    
        doAction() {
            this.toBase(this.children[0]).promise(); // used to work
        }
    
        promise() : T {
            return this.toSelf(); // 
        }
    }
    
    class Child extends Base<Child> {
        public myString: string;
    }
    
    function toThis() { return this; }
    
    new Child(toThis, x => x).promise().myString; // used to work
    
    0 讨论(0)
提交回复
热议问题