web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

Community site session details

Community site session details

Session Id :
Power Platform Community / Forums / Power Apps / Splitting Up A Large T...
Power Apps
Unanswered

Splitting Up A Large TypeScript Class

(0) ShareShare
ReportReport
Posted on by 156 Most Valuable Professional

Let's say I've extended the FormContext by creating a new TS class that wraps it, and adds helper functions.  This new ExtendedContext has functions like getDisplayValue(attName) which gets the attribute, handles it not being on the form, determines the attribute type, and appropriately returns what the "displayed value" is.  As I add more helper functions, the class get's bigger and bigger, which means I need to start splitting the class into more files, but I don't want the API to change. The consuming code should not have to know that it needs to create a DisplayExtendedContext class to call getDisplayValue, all functions should exist on the main extended context. What's the recommended approach?

 

My current approach feels wrong and looks like this:

 

// extendedContex.ts
import { DisplayContext } from "../context/display";

export class ExtendedContext implements XrmExt.ExtendedContext {
 public context: Xrm.FormContext // Actual Xrm.Client form context
 private display: DisplayContext;
 
 constructor(context: Xrm.FormContext){
	this.context = context;
	this.display = new DisplayContext(this);
 }
 
 public getDisplayValue(att: string): string {
	return display.getDisplayValue(att);
 }
}

// xrmExt.d.ts
declare namespace XrmExt {
	interface ExtendedContext {
		getDisplayValue(att: string): string;
	}
}

// ../context/display.ts
export class DisplayContext {
	private context: XrmExt.ExtendedContext;
	
	constructor(context: XrmExt.ExtendedContext){
		this.context = context;
	}
	
	public getDisplayValue(att: string): string {
		// Do logic here, with full access to the ExtendedContext
	}
}

 Here are the issues it has:

  1. I have to duplicate the pass throughs for ExtendedContext functions. So every function I add, I have to implement it in the smaller context class, and then add it as a pass through in the ExtendedContext class and to the ExtendedContext interface.  I'm lazy, I don't want to have to do that for every function.
  2. This one is more minor, but the ExtendedContext that is passed to the DisplayContext is not fully initialized, which could lead to null ref errors.  For example, if DisplayContext were to call a function on the XrmExt.ExtendedContext interface in it's constructor that it itself implements, the class level "display" field of the ExtendedContext class will not be populated, and a null ref exception would be thrown.  An "unspoken" rule of never access the ExendedContext from the constructor of one of the smaller classes would prevent this from ever being an issue.

I'm guessing Mixings might be the way forward here, but I'm just not sure.  Thoughts / Suggestions?

I have the same question (0)
  • Verified answer
    cchannon Profile Picture
    4,702 Moderator on at

    OK, this is a complex one, for sure, but I am not sure it is as complex as you think.

     

    Inheritance between classes in TS does not intrinsically mean that you must redeclare every member at every level. Maybe I am missing something you're trying to do here, but why do you think you need to redeclare every member? Try the below super-simple example in a raw TS file: 

    export class myclass{
     public aString: string;
     public aMethod: (() => void)
    }
    
    export class myOtherClass extends myclass{
     public aNumber: number;
     constructor(aNumber: number, aString: string) {
     super();
     this.aNumber = aNumber;
     this.aString = aString;
     }
    }
    
    let thing : myOtherClass = new myOtherClass(1,"thing");
    thing.aMethod();

    You'll see that even though myClass implements aMethod and myOtherClass does not, you can still invoke it on the class object instantiated as myOtherClass because myOtherClass extends myClass. And, even though myOtherClass does not have an explicitly declared member "aString" it can still use it in its constructor.

     

    This transitive property of class members extends as far as you would like your inheritance to go, so even if a child member is of a class 47 classes deep, it is still accessible, still usable in constructors and other contexts, and still extensible if you want to invert your model to be subclasses instead of a parent class construction, even if nowhere along the line it was explicitly re-declared.

     

  • Daryl LaBar Profile Picture
    156 Most Valuable Professional on at

    I was hoping to avoid chaining all of the inherited classes together, but this ended up being the approach I went with.  Now I just have to maintain the correct order of inheritance of all the classes and make sure there are no circular references.  One of the few times that I wish TypeScript had a C# feature (partial classes).

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Forum hierarchy changes are complete!

In our never-ending quest to improve we are simplifying the forum hierarchy…

Ajay Kumar Gannamaneni – Community Spotlight

We are honored to recognize Ajay Kumar Gannamaneni as our Community Spotlight for December…

Leaderboard > Power Apps

#1
WarrenBelz Profile Picture

WarrenBelz 717 Most Valuable Professional

#2
Michael E. Gernaey Profile Picture

Michael E. Gernaey 329 Super User 2025 Season 2

#3
Power Platform 1919 Profile Picture

Power Platform 1919 268

Last 30 days Overall leaderboard