Nxt3
Nxt3

Reputation: 2071

Possible to create an abstract property?

I have a property that looks like this in a Child class:

formModel = {
    motive: 0,
    coop: 0,
    leadership: 0,
    teamwork: 0,
    community: 0,
    professional: 0,
    role_model: 0,
    supportive: 0,
    problem_solving: 0
};

But in other child classes, this property is different.

formModel = {
    motive: 0,
    coop: 0,
    leadership: 0,
    teamwork: 0,
    community: 0,
    professional: 0,
    communication: 0,
    respect: 0,
    morale: 0,
    role_model: 0,
    supp_enviro: 0
};

The order of the attributes changes and the names change too.

I want to declare an abstract version of this property in its Parent class. Is this possible? I'm having no such luck with public abstract formModel: Object; in the parent.

Edit:

Here is the error I'm getting:

vendor.bundle.js:40839 Uncaught Error: Unexpected value 'undefined' declared by the module 'AppModule'
    at syntaxError (vendor.bundle.js:40839)
    at vendor.bundle.js:54719
    at Array.forEach (<anonymous>)
    at CompileMetadataResolver.webpackJsonp.../../../compiler/@angular/compiler.es5.js.CompileMetadataResolver.getNgModuleMetadata (vendor.bundle.js:54717)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._loadModules (vendor.bundle.js:66103)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._compileModuleAndComponents (vendor.bundle.js:66076)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler.compileModuleAsync (vendor.bundle.js:66005)
    at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_._bootstrapModuleWithZone (vendor.bundle.js:71695)
    at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_.bootstrapModule (vendor.bundle.js:71681)
    at Object.../../../../../src/main.ts (main.bundle.js:1339)

I noticed that I only get this error if I add the following method to my parent class, instead of the child class:

public handleRadioButtonChanges(event: Event): void {
    console.log("test");
}

Upvotes: 3

Views: 8553

Answers (2)

jcalz
jcalz

Reputation: 327849

The answer to the question as stated is emphatically yes, you can create abstract properties. I can do the following with no errors:

// what are the restrictions on FormModel? 
// See [@amal's answer](https://stackoverflow.com/a/46328720/2887218) 
// for discussion about this
interface FormModel {
  [key: string]: number;
}

abstract class Parent {
  public abstract formModel: FormModel;  
  public handleRadioButtonChanges(event: Event): void {
    console.log("test");
}
}

class Child extends Parent {
  formModel = {
    motive: 0,
    coop: 0,
    leadership: 0,
    teamwork: 0,
    community: 0,
    professional: 0,
    role_model: 0,
    supportive: 0,
    problem_solving: 0
  };
}

class AnotherChild extends Parent {
  formModel = {
    motive: 0,
    coop: 0,
    leadership: 0,
    teamwork: 0,
    community: 0,
    professional: 0,
    communication: 0,
    respect: 0,
    morale: 0,
    role_model: 0,
    supp_enviro: 0
  };
}

However, the error you're getting seems to be something specific to webpack, and I don't know what is causing it. When I compile with tsc there's no difference between the emitted JavaScript made with or without the public abstract formModel: FormModel; line. It's just type information, which tends not to find its way into JavaScript. You might need to give more info about your environment so someone can reproduce.

In any case, the problem you're having probably has very little to do with abstract properties per se, except that it is being exposed when you add that property to the parent class. Perhaps this GitHub issue is relevant? Or this SO question? I really don't know since I don't have any webpack expertise.

Upvotes: 5

amal
amal

Reputation: 3170

You can define an interface for it, if you are only concerned about its type.

export interface FormModel {
 motive: number;
 coop: number;
 leadership: number;
 teamwork: number;
 community: number;
 professional: number;
 role_model: number;
 supportive: number;
 problem_solving: number;
}

Then in child you could simply declare this formModel of the type FormModel defined in the parent (you also have to import this interface in the child component.ts file).

import { FormModel } from 'app/<Interface's location>';

formModel: FormModel;

EDIT

You could make them optional by adding ? to its declaration like motive?: number;, if that helps. So add this to attributes you feel are optional. Or simply only declare the properties that you think are present always (without optional) and then add a dynamic property like this.

export interface FormModel {
 motive: number;
 coop: number;
 leadership: number;
 teamwork: number;
 community: number;
 professional: number;
 role_model: number;
 supportive: number;
 problem_solving: number;
 [key: string]: any; // <-- leaving room for optional extra properties
}

Upvotes: 2

Related Questions