Pauline
Pauline

Reputation: 273

TypeScript: Use namespaced type argument in generic

I have a generic method

abstract run<T> (options: T): void;

And then in the implementation, say I want the type of T to be class B which is in namespace A. TSLint complains if I use

run <A.B> (options: A.B) : void 

The error is

Type '<A, B>(options: B) => void' is not assignable to type '<T>(options: T) => void'

It seems that the dot '.' is being read as ',' ? How should I pass the type?

Upvotes: 1

Views: 2801

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249476

If a method is generic in a base class it can't be implemented for just one type in the derived class. This would break OOP principles, as you couldn't use the derived class where the base class is expected:

namespace A {
    export class B { private x!: string}
}
abstract class Abs {
    abstract run<T>(p: T): void;
}
class Impl extends Abs{
    run(p: A.B) { } // We get an error here as we should but if this were allowed we would get the error below
}

let a: Abs = new Impl();
a.run(""); // Impl expects A.B, but Abs will let us pass in any T not ok

Note The syntax you use is also wrong, you can only specify concerte types in calls as generic type arguments, you can't use a type in as a type parameter in a function/method declaration. There is no syntax for this because it generally makes no sense as outlined above.

A good option would be to move the generic type parameter to the class instead:

namespace A {
    export class B { private x!: string}
}
abstract class Abs<T> {
    abstract run(p: T): void;
}
class Impl extends Abs<A.B>{
    run(p: A.B) { } // ok now
}

let a: Abs<A.B> = new Impl();
a.run(new A.B()); // type safe

Upvotes: 1

Related Questions