#Questions on Abstract Classes, with Abstract Methods, with extended parameters.

17 messages · Page 1 of 1 (latest)

final galleon
#

I want to extend a parameter as follow:

//abstract class and parent structures
interface A{
  label_1: string;
} 

abstract class A_class{
  //...
  abstract A_method(p: A): void;
}

then I want a child class with a child parameter

interface B extends A{
  label_2: number;
}

class B_class extends A_class{
  B_method(p_2: B){ //<-- does not work, it wants me to leave 'A' here.
                  // I want to inherit properties from A, 
                  // yet I want to add some addtional properties within B
                  // How would I do this? Is it possible? Is there a better way? 
    //do stuff with p_2
  }
}

I cannot seem to get B_method's parameters to work appropriately. Is there way? or am I just very wrong in my design?

Articles welcome, I have read the TS website already. I may need help understanding something I missed. As a self educated developer, I understand I have holes in my understanding. Please help me fill my missing information in, preferably in a kind way.

royal kayak
#

i'm not sure what you mean—B_method seems fine here:

mortal remnantBOT
#
mkantor#0

Preview:```ts
//abstract class and parent structures
interface A {
label_1: string
}

abstract class A_class {
//...
abstract A_method(p: A): void
}

interface B extends A {
label_2: number
}

class B_class extends A_class {
B_method(p_2: B) {}
}```

royal kayak
#

there's an error, but it doesn't have anything to do with B_method's parameters. it's because A_method is marked as abstract and doesn't have an implementation. if you were inheriting from a concrete A_class instead that error would go away

#

or alternatively you could mark B_class as abstract if it really shouldn't have an implementation yet

dense galleon
#

@final galleon There is no problem with code excpet the B_class should implement methods of A_class and the reason why B_method want you label_1 becasue the interface B extends A so you can remove the extends from interface and when calling method you can just provide the parameter label_2. and here is the updated version.

interface A{
      label_1: string;
  } 
    
 abstract class A_class{
      //...
    abstract A_method(p: A): void;
 }

    interface B {
      label_2: number;
    }
    
    class B_class extends A_class{
      A_method(p: A): void {
            // just implement
      }
      B_method(p_2: B){
        console.log(p_2)
      }
    }

const bb = new B_class();
bb.B_method({ label_2 : 3232 })
final galleon
#

That was a mistake on my part!

B_method is supposed to be the implementation of A_method, I get errors when p_2 is an instance of B and not A, Yet I want the extra parameters added with B.

royal kayak
#

if you write this, it will "work" (as in the type checker won't complain):

class B_class extends A_class{
  A_method(p_2: B){}
}

however, this is not actually sound. for historical reasons related to library compatibility (i think), typescript unsafely treats method parameter subtyping bivariantly, instead of contravariantly as it should (this article might help if you don't know what those terms mean). here's an example of why this is not safe:

mortal remnantBOT
#
mkantor#0

Preview:```ts
...
class B_class extends A_class{
A_method(p_2: B){
console.log(p_2.label_2.toLocaleString()) // this line throws if this method is called with an A
}
}

const bAsA: A_class = new B_class()
bAsA.A_method({ label_1: 'oops' }) // this will throw a runtime error
...```

final galleon
#
mortal remnantBOT
#

@final galleon Here's a shortened URL of your playground link! You can remove the full link from your message.

tamric#0

Preview:```ts
interface A {
label_1: string
}

abstract class A_class {
abstract A_method(p: A): void
}

interface B extends A {
label_2: number
}

class B_class extends A_class {
A_method(p_2: B) {
console.log(p_2) // this line throws if this method is called with an A
...```

royal kayak
#

i'm possibly misunderstanding, but do you expect no type errors in the last playground you sent? even though bAsA is typed as A_class, not B_class?

#

in this example, both a and b have the same type (A_class), because they are annotated as such:

const a: A_class = new A_class()
const b: A_class = new B_class()

you've told TS to forget about the fact that b is actually a subtype of A_class (namely, B_class). from here on out, there's nothing you can do with b that you can't do with a

royal kayak
final galleon
royal kayak
#

the problem is that you can always upcast (if B is a subtype of A then you can always treat values of type B as if they were As, which is basically the definition of subtyping). since A's A_method only needs label_1, passing just label_1 is always going to be allowed

#

do you need B_class to literally be a subtype of A_class? or are you just looking for some way to reuse code across these things?