Jake Jake - 2 days ago 5
TypeScript Question

implementation of abstract method not require same signature

I am creating a base class(here called top) that I want to use to create a blue print for all its children. I am doing this by making abstract functions on the base so that the children have to have an implementation of that in order to be valid. Here is an example

interface ITopData { }

abstract class top{

constructor() { }

abstract test<T extends ITopData>(data: T): void;

}

interface IBottomData extends ITopData { }

class bottom extends top {

constructor() { super() }

test<IBottomData>(data) { return }

}


This is the desired code however when i write a class like this

class bad extends top {

constructor() { super() }

test(data: string) { return }
//these implementations also dont cause any complaints
//test<T extends string>(data) { return }
//test() { return }

}


What I want is for typescript to complain that class "bad" doesnt properly extend class "top". When I write this out though I get no complaints from my intellisense or my transpiler.

edit: I do get errors if a child class were to not have any implementation of the function, but the errors go when using any of the implementations shown above.

Answer

One thing to remember is that string matches interface ITopData {} - since the interface has no properties, any object type will match it.

While it does not enforce the types based on the generic argument, if you specify the type for the parameter directly, you will get the compiler error. The semantics of the method parameter also stays the same.

interface ITopData {
    // the interface must have at least one mandatory property, 
    // otherwise any object will match it
    foo: number;
}

abstract class foo{
    constructor() { }

    abstract test(data: ITopData): void;
}

interface IBottomData extends ITopData { }

class bottom extends foo {
    constructor() { super() }

    test(data: IBottomData) { return }
}

class bad extends foo {
    constructor() { super() }

    test(data: string) { return; }
}

Alternatively, specify the generic type for the class instead of the method. This way you will also get compiler errors as soon as the types do not match

interface ITopData {
    // the interface must have at least one mandatory property, 
    // otherwise any object will match it
    foo: number;
}

abstract class foo<T extends ITopData>{
    constructor() { }

    abstract test(data: T): void;
}

interface IBottomData extends ITopData { }

class bad1 extends foo<IBottomData> {
    constructor() { super() }

    test(data: string) { return }
}

class bad2 extends foo<string> {
    constructor() { super() }

    test(data: string) { return; }
}
Comments