typescript reference own type in return type





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







1















I have a base class ApiModel:



class ApiModel {
static async fetch (params = {}, Model = this, apiPath = this.apiPath): Promise<any | PaginatedResponse> {
let { data } = await axios.get(apiPath, { params })
return Model.transformResponse(data)
}
}


and models that inherit from it:



class User extends ApiModel {
}


Typescript does not like my return definition (any) in combination with the variable type User:



let users: User = await User.fetch() // Assigned expression type any | PaginatedResponse is not assignable to type User


How can I replace any without explicitly using User (it needs to be generic, based on extended class)










share|improve this question


















  • 1





    FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

    – Titian Cernicova-Dragomir
    Jan 4 at 12:12








  • 1





    Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

    – Titian Cernicova-Dragomir
    Jan 4 at 12:15




















1















I have a base class ApiModel:



class ApiModel {
static async fetch (params = {}, Model = this, apiPath = this.apiPath): Promise<any | PaginatedResponse> {
let { data } = await axios.get(apiPath, { params })
return Model.transformResponse(data)
}
}


and models that inherit from it:



class User extends ApiModel {
}


Typescript does not like my return definition (any) in combination with the variable type User:



let users: User = await User.fetch() // Assigned expression type any | PaginatedResponse is not assignable to type User


How can I replace any without explicitly using User (it needs to be generic, based on extended class)










share|improve this question


















  • 1





    FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

    – Titian Cernicova-Dragomir
    Jan 4 at 12:12








  • 1





    Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

    – Titian Cernicova-Dragomir
    Jan 4 at 12:15
















1












1








1








I have a base class ApiModel:



class ApiModel {
static async fetch (params = {}, Model = this, apiPath = this.apiPath): Promise<any | PaginatedResponse> {
let { data } = await axios.get(apiPath, { params })
return Model.transformResponse(data)
}
}


and models that inherit from it:



class User extends ApiModel {
}


Typescript does not like my return definition (any) in combination with the variable type User:



let users: User = await User.fetch() // Assigned expression type any | PaginatedResponse is not assignable to type User


How can I replace any without explicitly using User (it needs to be generic, based on extended class)










share|improve this question














I have a base class ApiModel:



class ApiModel {
static async fetch (params = {}, Model = this, apiPath = this.apiPath): Promise<any | PaginatedResponse> {
let { data } = await axios.get(apiPath, { params })
return Model.transformResponse(data)
}
}


and models that inherit from it:



class User extends ApiModel {
}


Typescript does not like my return definition (any) in combination with the variable type User:



let users: User = await User.fetch() // Assigned expression type any | PaginatedResponse is not assignable to type User


How can I replace any without explicitly using User (it needs to be generic, based on extended class)







typescript






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 4 at 12:05









ChrisChris

2,67152361




2,67152361








  • 1





    FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

    – Titian Cernicova-Dragomir
    Jan 4 at 12:12








  • 1





    Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

    – Titian Cernicova-Dragomir
    Jan 4 at 12:15
















  • 1





    FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

    – Titian Cernicova-Dragomir
    Jan 4 at 12:12








  • 1





    Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

    – Titian Cernicova-Dragomir
    Jan 4 at 12:15










1




1





FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

– Titian Cernicova-Dragomir
Jan 4 at 12:12







FYI: The error you are getting is not due to any vs User it due to the union with PaginatedResponse

– Titian Cernicova-Dragomir
Jan 4 at 12:12






1




1





Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

– Titian Cernicova-Dragomir
Jan 4 at 12:15







Where is PaginatedResponse coming from ? Shouldn't it also be generic to allow for model type? I can provide the solution to how to make the static method on the base class work for derived classes, but there are other issues with your code

– Titian Cernicova-Dragomir
Jan 4 at 12:15














1 Answer
1






active

oldest

votes


















2














The error you are getting is not due to any vs User it due to the union with PaginatedResponse.



A union between any and PaginatedResponse and will not be assignable to User. You need to use a type-guard to distinguish between the array result and the PaginatedResponse



So this will work event with any (since any is assignable to any other type including User)



let result = await User.fetch()
if(result instanceof Array) {
const user: User = result;
}else {
const paged = result;
}


That being said, you should still avoid any (like the plague IMO, if you don't know the type prefer unknown (see here for unknown vs any))



To get the type of the current class in the static method you can use a generic type parameter in conjunction with the this parameter annotation.



The exact solution may vary on whether the class is abstract or not and on whether the constructor has parameters or not (and whether derived types have different parameter signatures or not).



The solution below works for non-abstract base class and if derived classes have the same constructor signature (or compatible) as the base class.



interface PaginatedResponse<T> {
start: number;
end: number;
data: T
}
class ApiModel {
static apiPath = ""
static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
return null!;
}
}
class User extends ApiModel {
}

(async function (){
let result = await User.fetch()
if(result instanceof Array) {
const user = result; // is User
}else {
const paged = result; // PaginatedResponse<User>
}
})()


Note I filled in PaginatedResponse with an interface as I was not sure what that type looked like, if the type is under your control I would make it generic to reflect the returned result type.






share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54038654%2ftypescript-reference-own-type-in-return-type%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














    The error you are getting is not due to any vs User it due to the union with PaginatedResponse.



    A union between any and PaginatedResponse and will not be assignable to User. You need to use a type-guard to distinguish between the array result and the PaginatedResponse



    So this will work event with any (since any is assignable to any other type including User)



    let result = await User.fetch()
    if(result instanceof Array) {
    const user: User = result;
    }else {
    const paged = result;
    }


    That being said, you should still avoid any (like the plague IMO, if you don't know the type prefer unknown (see here for unknown vs any))



    To get the type of the current class in the static method you can use a generic type parameter in conjunction with the this parameter annotation.



    The exact solution may vary on whether the class is abstract or not and on whether the constructor has parameters or not (and whether derived types have different parameter signatures or not).



    The solution below works for non-abstract base class and if derived classes have the same constructor signature (or compatible) as the base class.



    interface PaginatedResponse<T> {
    start: number;
    end: number;
    data: T
    }
    class ApiModel {
    static apiPath = ""
    static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
    return null!;
    }
    }
    class User extends ApiModel {
    }

    (async function (){
    let result = await User.fetch()
    if(result instanceof Array) {
    const user = result; // is User
    }else {
    const paged = result; // PaginatedResponse<User>
    }
    })()


    Note I filled in PaginatedResponse with an interface as I was not sure what that type looked like, if the type is under your control I would make it generic to reflect the returned result type.






    share|improve this answer




























      2














      The error you are getting is not due to any vs User it due to the union with PaginatedResponse.



      A union between any and PaginatedResponse and will not be assignable to User. You need to use a type-guard to distinguish between the array result and the PaginatedResponse



      So this will work event with any (since any is assignable to any other type including User)



      let result = await User.fetch()
      if(result instanceof Array) {
      const user: User = result;
      }else {
      const paged = result;
      }


      That being said, you should still avoid any (like the plague IMO, if you don't know the type prefer unknown (see here for unknown vs any))



      To get the type of the current class in the static method you can use a generic type parameter in conjunction with the this parameter annotation.



      The exact solution may vary on whether the class is abstract or not and on whether the constructor has parameters or not (and whether derived types have different parameter signatures or not).



      The solution below works for non-abstract base class and if derived classes have the same constructor signature (or compatible) as the base class.



      interface PaginatedResponse<T> {
      start: number;
      end: number;
      data: T
      }
      class ApiModel {
      static apiPath = ""
      static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
      return null!;
      }
      }
      class User extends ApiModel {
      }

      (async function (){
      let result = await User.fetch()
      if(result instanceof Array) {
      const user = result; // is User
      }else {
      const paged = result; // PaginatedResponse<User>
      }
      })()


      Note I filled in PaginatedResponse with an interface as I was not sure what that type looked like, if the type is under your control I would make it generic to reflect the returned result type.






      share|improve this answer


























        2












        2








        2







        The error you are getting is not due to any vs User it due to the union with PaginatedResponse.



        A union between any and PaginatedResponse and will not be assignable to User. You need to use a type-guard to distinguish between the array result and the PaginatedResponse



        So this will work event with any (since any is assignable to any other type including User)



        let result = await User.fetch()
        if(result instanceof Array) {
        const user: User = result;
        }else {
        const paged = result;
        }


        That being said, you should still avoid any (like the plague IMO, if you don't know the type prefer unknown (see here for unknown vs any))



        To get the type of the current class in the static method you can use a generic type parameter in conjunction with the this parameter annotation.



        The exact solution may vary on whether the class is abstract or not and on whether the constructor has parameters or not (and whether derived types have different parameter signatures or not).



        The solution below works for non-abstract base class and if derived classes have the same constructor signature (or compatible) as the base class.



        interface PaginatedResponse<T> {
        start: number;
        end: number;
        data: T
        }
        class ApiModel {
        static apiPath = ""
        static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
        return null!;
        }
        }
        class User extends ApiModel {
        }

        (async function (){
        let result = await User.fetch()
        if(result instanceof Array) {
        const user = result; // is User
        }else {
        const paged = result; // PaginatedResponse<User>
        }
        })()


        Note I filled in PaginatedResponse with an interface as I was not sure what that type looked like, if the type is under your control I would make it generic to reflect the returned result type.






        share|improve this answer













        The error you are getting is not due to any vs User it due to the union with PaginatedResponse.



        A union between any and PaginatedResponse and will not be assignable to User. You need to use a type-guard to distinguish between the array result and the PaginatedResponse



        So this will work event with any (since any is assignable to any other type including User)



        let result = await User.fetch()
        if(result instanceof Array) {
        const user: User = result;
        }else {
        const paged = result;
        }


        That being said, you should still avoid any (like the plague IMO, if you don't know the type prefer unknown (see here for unknown vs any))



        To get the type of the current class in the static method you can use a generic type parameter in conjunction with the this parameter annotation.



        The exact solution may vary on whether the class is abstract or not and on whether the constructor has parameters or not (and whether derived types have different parameter signatures or not).



        The solution below works for non-abstract base class and if derived classes have the same constructor signature (or compatible) as the base class.



        interface PaginatedResponse<T> {
        start: number;
        end: number;
        data: T
        }
        class ApiModel {
        static apiPath = ""
        static async fetch<T extends typeof ApiModel>(this: T, params = {}, Model = this, apiPath = this.apiPath): Promise<Array<InstanceType<T>> | PaginatedResponse<InstanceType<T>>> {
        return null!;
        }
        }
        class User extends ApiModel {
        }

        (async function (){
        let result = await User.fetch()
        if(result instanceof Array) {
        const user = result; // is User
        }else {
        const paged = result; // PaginatedResponse<User>
        }
        })()


        Note I filled in PaginatedResponse with an interface as I was not sure what that type looked like, if the type is under your control I would make it generic to reflect the returned result type.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 4 at 12:52









        Titian Cernicova-DragomirTitian Cernicova-Dragomir

        74.2k35371




        74.2k35371
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54038654%2ftypescript-reference-own-type-in-return-type%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Monofisismo

            Angular Downloading a file using contenturl with Basic Authentication

            Olmecas