How to make a field required in all children in TypeScript? - javascript

Suppose I have a class Base, how do I make all children inherited from Base implements a certain field on its own?
For example, Base has a required member function func(), A extends Base and B extends A. I want to make func() definition required in both A and B.
Can I do this and how? Thanks!

To make definition required you have to use interfaces:
interface MyPerfectlyNamedInterface {
func(): any; // no definition here, since interfaces are inherently abstract
}
class Base implements MyPerfectlyNamedInterface {
func(): any { /* definition is required */ }
}
// note that A does _not_ extend Base
class A implements MyPerfectlyNamedInterface {
func(): any { /* definition is required */ }
}
class B implements MyPerfectlyNamedInterface {
func(): any { /* definition is required */ }
}
However, if child class extends base class that has definition for your function (e.g., if A would extend Base and/or B would extend A), then definition is again not required:
interface MyPerfectlyNamedInterface {
func(): any;
}
class Base implements MyPerfectlyNamedInterface {
func(): any { /* definition is required */ }
}
// note that A _does_ extend Base
class A extend Base implements MyPerfectlyNamedInterface {
func(): any { /* definition is not required */ }
}
class B extend A implements MyPerfectlyNamedInterface {
func(): any { /* definition is not required */ }
}
So, I guess, that's not really possible with your setup.
Also, you can sort of achieve this using abstract classes, but again, it won't "cascade" down to child classes as you want:
abstract class Base {
abstract func(): any;
}
class A extends Base {
func(): any { /* definition is required */ }
}
class B extends A {
func(): any { /* definition is not required */ }
}

You can mark the method abstract in base class like this.
abstract class Base {
abstract func(): void;
}
class A extends Base {
func(): void {
console.log("Doing something in A class");
}
}
class B extends Base {
func(): void {
console.log("Doing something in B class");
}
}

Related

Why I don't get compile time error when I am not implementing some method from my interface which is implemented in base class?

I have the following code
interface IDownload {
downloadFile(): void;
}
class BaseClass implements IDownload {
downloadFile(): void {
console.log('some logic here');
}
}
class Sub extends BaseClass {
}
so my sub class has access to the methods from BaseClass because we are extending from that class.
My base class implement some method from interface.
When i try to extend the class and implement again the same interface
class Sub extends BaseClass implements IDownload {
}
I don't get compile time error that i need to implement the method from IDownload. I guees it is like that because it sees that the base class already implements it.
But i want to have that check also here in my sub class because i want to have the interface contract in the base class where all the methhods will exist on the sub class.
How can i do this ?
If you want all the implementation in the sub class, why don't you just implement the interface in the sub class?
interface IDownload {
downloadFile(): void;
}
class BaseClass {
}
class Sub extends BaseClass implements IDownload {
downloadFile(): void {
console.log('some logic here');
}
}

Typescript optional parameters overload

I have a class e.g.
class SomeClass {
someMethod(param1: string; param2?: string) { ... }
}
And another one that extends from fore
class AnotherClass extends SomeClass {
someMethod(param1: string) { ... }
}
Also I've got a third class that uses instance of one of these classes as generic e.g.
class ThirdClass<T extends SomeClass> {
instanceClass: T;
}
So I'm getting an error that someMethod in AnotherClass is not compatible with SomeClass, to solve the problem I should make an overload for someMethod in SomeClass :
someMethod(param1: string); // <-- overload
someMethod(param1: string; param2?: string) { ... }
Is there any other way to say TS that everything is ok?

Assigning child class to a parent class typed property

I do have the following 2 base clases:
class BaseModel {}
class BaseService{
protected model:BaseModel;
}
Now I want to implement BaseHelper and BaseService for a specific use case and assign a derived class to my property.
class MyModel extends BaseModel{
constructor(param:string){
super();
}
}
class MyService extends BaseService {
model = MyModel;
}
However, this gives me the error Type 'typeof MyModel' is not assignable to type 'BaseModel'.
Important: I want to attach the class MyModel, not an instance of the class MyModel!
You need to instantiate MyModel using the new keyword (new MyModel()).
You assigned the actual class (model = MyModel) instead of an instance of it.
Also, you might want to make BaseService generic:
class BaseModel {}
class BaseService<T extends BaseModel> {
protected model: T;
constructor(model: T) {
this.model = model;
}
}
class MyModel extends BaseModel{}
class MyService extends BaseService<MyModel> {
constructor() {
super(new MyModel());
}
}
(code in playground)
Edit
If you need the class and not the instance, then something like:
class BaseModel {}
type BaseModelConstructor = { new(): BaseModel };
class BaseService {
protected modelCtor: BaseModelConstructor;
}
class MyModel extends BaseModel {}
class MyService extends BaseService {
modelCtor = MyModel;
}
(code in playground)
Or you can use generics here as well:
class BaseModel {}
type BaseModelConstructor<T extends BaseModel> = { new(): T };
class BaseService<T extends BaseModel> {
protected modelCtor: T;
}
class MyModel extends BaseModel {}
class MyService extends BaseService<BaseModel> {
modelCtor = MyModel;
}
(code in playground)
If your derived classes have different ctor signatures then you can either deal with it in the base ctor type:
type BaseModelConstructor<T extends BaseModel> = { new(...args: any[]): T };
Here you can pass any count and kind of parameters, but you can also supply different signatures:
type BaseModelConstructor<T extends BaseModel> = {
new(): T;
new(str: string): T;
new(num: number, bool: boolean): T;
};
But you can also use a different type per derived class:
type MyModelConstructor = { new(param: string): MyModel };
model should be an instance of MyModel:
class MyModel extends BaseModel{}
class MyService extends BaseService {
model = new MyModel()
}
Use instance of BaseModel
class MyService extends BaseService {
model = new MyModel();
}

Multiple Class Inheritance In TypeScript

What are ways to get around the problem of only being allowed to extend at most one other class.
class Bar {
doBarThings() {
//...
}
}
class Bazz {
doBazzThings() {
//...
}
}
class Foo extends Bar, Bazz {
doBarThings() {
super.doBarThings();
//...
}
}
This is currently not possible, TypeScript will give an error. One can overcome this problem in other languages by using interfaces but solving the problem with those is not possible in TypeScript.
Suggestions are welcome!
This is my workaround on extending multiple classes. It allows for some pretty sweet type-safety. I have yet to find any major downsides to this approach, works just as I would want multiple inheritance to do.
First declare interfaces that you want to implement on your target class:
interface IBar {
doBarThings(): void;
}
interface IBazz {
doBazzThings(): void;
}
class Foo implements IBar, IBazz {}
Now we have to add the implementation to the Foo class. We can use class mixins that also implements these interfaces:
class Base {}
type Constructor<I = Base> = new (...args: any[]) => I;
function Bar<T extends Constructor>(constructor: T = Base as any) {
return class extends constructor implements IBar {
public doBarThings() {
console.log("Do bar!");
}
};
}
function Bazz<T extends Constructor>(constructor: T = Base as any) {
return class extends constructor implements IBazz {
public doBazzThings() {
console.log("Do bazz!");
}
};
}
Extend the Foo class with the class mixins:
class Foo extends Bar(Bazz()) implements IBar, IBazz {
public doBarThings() {
super.doBarThings();
console.log("Override mixin");
}
}
const foo = new Foo();
foo.doBazzThings(); // Do bazz!
foo.doBarThings(); // Do bar! // Override mixin
This is possible with interfaces:
interface IBar {
doBarThings();
}
interface IBazz {
doBazzThings();
}
class Foo implements IBar, IBazz {
doBarThings() {}
doBazzThings(){}
}
But if you want implementation for this in a super/base way, then you'll have to do something different, like this:
class FooBase implements IBar, IBazz{
doBarThings() {}
doBazzThings(){}
}
class Foo extends FooBase {
doFooThings(){
super.doBarThings();
super.doBazzThings();
}
}
Not really a solution to your problem, but it is worth to consider to use composition over inheritance anyway.
Prefer composition over inheritance?

How can I implement a method from a class I extend from in Typescript?

class Abc {
doTask() {
return 1;
}
}
class Def extends Abc {
// How can I access doTask() here?
}
I would like to implement that method doTask() inside of the class Def. Can someone give me advice on how I can do this.
Use super if you plan to override it e.g. :
class Abc {
doTask() {
return 1;
}
}
class Def extends Abc {
doTask(){
return super.doTask();
}
}
or just this if you don't e.g:
class Eef extends Abc {
foo(){
return this.doTask();
}
}
You just need to use this.doTask() in a member of Def. E.g:
class Abc {
doTask() {
return 1;
}
}
class Def extends Abc {
// How can I access doTask() here?
likeThis() {
return this.doTask() + 1;
}
}
you can override it, overload it and use it in the child class equally to the parent one, for instance:
class A{
public void dotask(){
//blabla
}
}
Class B extends A{
//overriding
public void dotask(){
}
//overloading
public void dotask(int a){
}
//simple use
public void anotherTask(){
doTask();
}
}

Categories

Resources