简体   繁体   中英

Abstract function return type in typescript

It seems that defining an abstract function with generic return type is not possible with typescript (I am using ts 3.2.4) or I am missing something.

For instance:

abstract class Foo {
    abstract func<T>() : T;
}

class Bazz extends Foo {
    func() { return 1; }
}

will give an error:

TS2416: Property 'func' in type 'Bazz' is not assignable to the same property in base type 'Foo'. Type '() => number' is not assignable to type '() => T'. Type 'number' is not assignable to type 'T'.

So, is it possible to define an abstract function that will have the generic return type?

Edit:

So, it turns out that using unknown work as expected and it can be used as the return type in an abstract function. But, let's consider this:

abstract class Foo{
    getFuncResult() {
        return this.func();
    }
    abstract func() : unknown;
}

class Bazz extends Foo {
    func() { return 1; }
}

let foo: Foo = new Bazz();
foo.func(); // unknown

let bazz = new Bazz() 
bazz.func() // number
bazz.getFuncResult() // unknown

I would expect that the getFuncResult on the Bazz will have the same type signature as derived func (number). So, this is more a question about type inference for Typescript.

The problem is where you put the type parameter. If the type parameter is on the method, then that method must be generic in derived class. The contract that is specified by that method means we must always be able to call it with any T (ie the caller decides with what T to call). So this code need to work:

let a: Foo = new Bazz()
a.fun<string>() // method is generic caller decides `T`

You want to place the type parameter on the class, and fix the type parameter when inheriting in Bazz

abstract class Foo <T>{
    abstract func() : T;
}

class Bazz extends Foo<number> {
    func() { return 1; }
}

let foo: Foo<number> = new Bazz();
foo.func(); //ok result is numebr

let fooStr: Foo<string> = new Bazz() // error, different T 

Edit

If you don't care what the return type is in the base class and you just want the derived class to create the method, you could use unknown as the return type. If you have a reference to the abstract class and invoke the method it will return unknown if you have a reference to a derived class it will return the apropriate type:

abstract class Foo{
    abstract func() : unknown;
}

class Bazz extends Foo {
    func() { return 1; }
}

let foo: Foo = new Bazz();
foo.func(); // unknown

let bazz = new Bazz() 
bazz.func() // number

Edit

With regard to using func in another function and expecting the type of that to be relative to func typescript will not help you there, at least not by default. By default getFuncResult will be typed with what information is known in the base class. Without using a class type parameter (and I do think you should look into that) a solution is to use a type query on the polymorphic this type. This will type the return relative to whatever the current class is but you will need to use a type assertion inside the function to get things to work:

abstract class Foo{
    getFuncResult() : ReturnType<this['func']> {
        return this.func() as any;
    }
    abstract func() : unknown;
}

class Bazz extends Foo {
    func() { return 1; }
}

let foo: Foo = new Bazz();
foo.func(); // unknown

let bazz = new Bazz() 
bazz.func() // number
bazz.getFuncResult() // number

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM