Access members of outer class in TypeScript - oop

Since TypeScript 1.6, we can easily create inner classes with class expressions. In other OOP-centric languages like Java, inner classes can access members of the outer class, even private ones.
This behavior is similar to concept of closures, where function could access variables from the scope in which it was defined.
Why I can't achieve this in TypeScript? Does specification of classes in ECMAScript 2015 plays role here?
Code that presents expected behavior:
class OuterClass {
private outerField = 1337;
public InnerClass = class {
public accessOuter() {
return this.outerField; // outerField not defined
}
}
}
var outer = new OuterClass();
var inner = new outer.InnerClass();
var win = inner.accessOuter();

It's easier to understand why you can't do that if you look at the compiled javascript of your code:
var OuterClass = (function () {
function OuterClass() {
this.outerField = 1337;
this.InnerClass = (function () {
function class_1() {
}
class_1.prototype.accessOuter = function () {
return this.outerField; // outerField not defined
};
return class_1;
}());
}
return OuterClass;
}());
As you can see, outerField is defined as a member of OuterClass like so:
this.outerField = 1337;
When you try to access it in your InnerClass you do:
return this.outerField;
But the this here is the instance of class_1 and not OuterClass so there's no outerField in this.
Also, you have no access from the inner class to the instance of the outer class.
The way this is solved in java is like so:
class OuterClass {
private int outerField = 1337;
public class InnerClass {
public int accessOuter() {
return OuterClass.this.outerField;
}
}
}
But there's no equivalent to OuterClass.this.outerField in typescript/javascript.
Look at typescript inner classes more like static inner classes in java, but here too you'll only be able to access public properties:
class OuterClass {
public static outerField = 1337; // has to be public
public InnerClass = class {
public accessOuter() {
return OuterClass.outerField;
}
}
}
You can pass an instance of the outer class to the inner class:
class OuterClass {
public outerField = 1337;
public InnerClass = class {
constructor(private parent: OuterClass) {}
public accessOuter() {
return this.parent.outerField;
}
}
}
But again, you'll need to have outerField public.
Edit
In case you want to achieve something that will simulate the needed behavior (that is, the inner class instance will have access to a private outer class members), then you can do something like this:
interface OuterClassProxy {
outerField: number;
}
interface IInnerClass {}
class OuterClass {
private outerField = 1337;
static InnerClass = class implements IInnerClass {
constructor(private parent: OuterClassProxy) {}
public accessOuter() {
return this.parent.outerField;
}
}
public createInnerClass(): IInnerClass {
let outerClassInstance = this;
return new OuterClass.InnerClass({
get outerField(): number {
return outerClassInstance.outerField;
},
set outerField(value: number) {
outerClassInstance.outerField = value;
}
});
}
}
It's quite a lot of work, but it will do it.

#Nitzan 's answer is great. I just wanted to add that I came up with this recently, maybe it helps:
class Outer {
constructor() {
this.val = 1337;
}
get Inner() {
let Outer = this;
return class {
accessVal() { return Outer.val; }
}
}
}
new (new Outer()).Inner().accessVal(); // 1337

Here is the correct way to do this in Typescript:
class OuterClass {
private outerField = 1337;
get InnerClass() {
const thatOuterField = this.outerField // <-- Notice this addition
return class {
public accessOuter() {
return thatOuterField; // outerField not defined
}
}
}
}
let outer = new OuterClass();
let inner = new outer.InnerClass();
let win = inner.accessOuter();
alert(win); // test works!
No need for anything convoluted.

This one did not work so bad for me:
function use<T>(value: T) {return new class {with<U>(f: (value: T) => U) {return f(value)}}}
class OuterClass {
private outerField = 1337;
InnerClass = use(this).with(outerThis => class {
accessOuter() {
return outerThis.outerField; // outerField not defined
}
}
}
const outer = new OuterClass()
const inner = new outer.InnerClass()
const win = inner.accessOuter()
console.log(win)

Related

Access static mathod before using »super«

there is this class hierarchy:
class A {
constructor (obj) {
this.obj = obj
}
}
class B extends A {
static createObj () {
return {from: 'B'};
}
constructor () {
const obj = B.createObj();
super(obj);
}
}
I would like to extend this such that:
class C extends B {
static createObj () {
return { from: 'C' };
}
}
//such that:
console.log(new C().obj.from) // 'C'
BUT therefore I need to change const obj = B.createObj() to something like: const obj = Object.getPrototypeOf(this).constructor.createObj();, what is throwing this error:
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
So basically I would like to override a method that creates an object to be used within the super() call. Since this cannot be used before that, I chose to use a static method. Is there any way to reference the static method, without using this and without overriding the constructor as well?
If you really want your this.obj=obj to be done only in class A for some reason, then I would do:
class A {
constructor(obj) {
this.obj = obj
}
}
class B extends A {
static createObj() {
return { from: 'B' };
}
constructor(obj) {
if (!obj) obj = B.createObj();
super(obj);
}
}
class C extends B {
static createObj() {
return { from: 'C' };
}
constructor(obj) {
if (!obj) obj = C.createObj();
super(obj);
}
}
console.log(new C().obj.from)
Output:
"C"
But in my opinion the best OOP approach would be this:
class A {
constructor(obj) {
this.obj = obj
}
}
class B extends A {
static createObj() {
return { from: 'B' };
}
constructor(obj) {
super(obj);
this.obj = B.createObj();
}
}
class C extends B {
static createObj() {
return { from: 'C' };
}
constructor(obj) {
super(obj);
this.obj = C.createObj();
}
}
console.log(new C().obj.from)
Output:
"C"
The 2nd approach allows to satisfy the pattern "call super before doing anything else" that can prevent bugs.
It's up to you to chose which one better suits your needs, but both prints "C" without requiring Object.getPrototypeOf(this).constructor.createObj()

Typescript how to declare a function that returns a lowest common denominator type?

i want declare a function that returns a common type or its extended type
interface Common {
id: number;
}
interface AdditionalInformation extends Common {
myname: string;
}
Surely the function returns an object containing the id property
and wishing it could also return the myname property
I tried to declare the function like this:
export class Lib {
public static lowestCommonDenominator <T extends Common>(): Common {
const a: Common = { id: 1 };
return a;
}
public static firstCaseFunction(): Common {
const ok: Common = this.lowestCommonDenominator();
return ok;
}
public static secondCaseFunction(): AdditionalInformation {
// Property 'myname' is missing in type 'Common' but required in type 'AdditionalInformation'.ts(2741)
const ko: AdditionalInformation = this.lowestCommonDenominator();
return ko;
}
}
But when I assign the function to an extended type, I get the error:
Property 'myname' is missing in type 'Common' but required in type
'AdditionalInformation'.ts(2741)
Is it possible to implement what I want?
This code snippet removes the error
export class Lib {
public static lowestCommonDenominator <T extends Common>(): T {
const a: Common = { id: 1 };
return a as T;
}
public static firstCaseFunction(): Common {
const ok: Common = this.lowestCommonDenominator();
return ok;
}
public static secondCaseFunction(): AdditionalInformation {
const ko: AdditionalInformation = this.lowestCommonDenominator<AdditionalInformation>();
return ko;
}
}

How to create a MXBean with control methods?

We are planning to implement some behaviour control in our
CordApp, for testing purposes. Is that possible to create a
M(X)Bean, accessible via JMX, which is going to change some
internal flags in our CordApp ? If this is not a good design
choice, please inform the best practice to follow.
Basically, we have a set of flags, like these:
abstract class BaseFlow() : FlowLogic<SignedTransaction>() {
var flagBehaviourOne : Boolean = true
var flagBehaviourTwo : Boolean = true
var flagBehaviourThree: Boolean = true
var flagBehaviourFour : Boolean = true
...
}
then, in some implementing class, we have something like this:
object SomeFlow {
#InitiatingFlow
class Initiator(private val destinatario: Party,
private val parameter: StateObject,
private val isAnonymous: Boolean = false,
private val pointer: Any) : BaseFlow() {
...
#Suspendable
override fun call(): SignedTransaction {
if (flagBehaviourOne || flagBehaviorTwo) {
// enforce some specific behaviour
}
...
} // end of SomeFlow.Initiator
...
} // end of SomeFlow
I have (partially) solved my problem.
I have added a new object class, along with its jmx interface :
package vfalcao.example.jmx
import java.lang.management.ManagementFactory
import javax.management.MXBean
import javax.management.ObjectName
#MXBean
interface BehaviourControlMXBean {
fun setBehaviourOne(newValue: String)
fun isBehaviourOne() : String
...
// other "behaviours" ommited for brevity
}
object BehaviourControl : BehaviourControlMXBean {
// internal data
...
init {
val objectName = ObjectName("vfalcao.example.jmx:type=BehaviourControl,name=def")
val platformMBeanServer = ManagementFactory.getPlatformMBeanServer()
platformMBeanServer.registerMBean(this, objectName)
}
}
then, in my BaseFlow class:
abstract class BaseFlow() : FlowLogic<SignedTransaction>() {
companion object {
...
init {
println("${BehaviourControl}")
}
...
fun test() {
var behaviour1 = ((BehaviourControl.props["behaviour1"] as String).toBoolean())
if (behaviour1) {
// do something controlled by behaviour1
}
}
}
...
}

Hiding base class constructor parameters in Kotlin

I am trying to understand how to hide a base constructor parameter in a subclass in kotlin. How do you put a facade over a base constructor? This doesn't work:
import com.android.volley.Request
import com.android.volley.Response
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private fun hiddenListener() = Response.ErrorListener {
/* super secret listener */
}
...
}
I think I understand the problem:
During construction of a new instance of a derived class, the base
class initialization is done as the first step (preceded only by
evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
I'm trying to solve this problem for Volley, where I need my custom request to be be a Request so that it can be passed into a RequestQueue. It would be easier of RequestQueue took in some kind of interface but since it doesn't I have to subclass. There are other ways I can hide these complexities from the caller, but this limitation has come up for me other times in Kotlin and I'm not sure how to solve it.
I am not familiar with volley but I tried to come up with an example that should give you some insight how to solve your problem. What you can do is use a companion object:
interface MyListener {
fun handleEvent()
}
open class Base<T>(anything: Any, val listener: MyListener) { // this would be your Request class
fun onSomeEvent() {
listener.handleEvent()
}
}
class Derived(anything: Any) : Base<Any>(anything, hiddenListener) { // this would be your MyCustomRequest class
private companion object {
private val hiddenListener = object : MyListener {
override fun handleEvent() {
// do secret stuff here
}
}
}
}
So if you apply this to your problem, the result should look something like this:
class MyCustomRequest(url: String)
: Request<String>(Request.Method.POST, url, hiddenListener) {
private companion object {
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
}
...
}
A different way would be to use a decorator, create your Request withing that decorator and just delegate the calls to it:
class Decorator(anything: Any) {
private var inner: Base<Any>
private val hiddenListener: MyListener = object : MyListener {
override fun handleEvent() { }
}
init {
inner = Base(anything, hiddenListener)
}
}
And once again for your example that would look like this:
class MyCustomRequest(url: String) {
private var inner: Request<String>
private val hiddenListener = Response.ErrorListener {
/* super secret listener */
}
init {
inner = Request<String>(Request.Method.POST, url, hiddenListener)
}
...
}

How to mock a top-level-function in kotlin with jmockit

Assuming the I have a function to be test below, declare at the file named "Utils.kt"
//Utils.kt
fun doSomething() = 1
Then we create a test class to test it
//UtilsTest.kt
#RunWith(JMockit::class)
class UtilsTest {
#Test
fun testDoSomething() {
object : Expectation() {
init {
doSomething()
result = 2
}
}
assertEquals(2, doSomething())
}
}
I want to mock doSomething, make it return 2, but it won't work, actual result is 1
Is there any workaround for this purpose?
A workaround mock it in Java side as you cannot reference the UtilsKt class from Kotlin files.
#RunWith(JMockit.class)
public final class UtilsFromJavaTest {
#Test
public final void testDoSomething(#Mocked #NotNull final UtilsKt mock) {
new Expectations() {
{
UtilsKt.doSomething();
this.result = 2;
}
};
Assert.assertEquals(2, UtilsKt.doSomething());
}
}
Thanks to #aristotll, we can simply extends the workaround to make it more easier to use.
first, declare a java class that return the UtilsKt class
//TopLevelFunctionClass.java
public class TopLevelFunctionClass {
public static Class<UtilsKt> getUtilsClass() {
return UtilsKt.class
}
}
then, mock this class in expectation using partial mock
//UtilsTest.kt
#RunWith(JMockit::class)
class UtilsTest {
#Test
fun testDoSomething() {
object : Expectation(TopLevelFunctionClass.getUtilsClass()) {
init {
doSomething()
result = 2
}
}
assertEquals(2, doSomething())
}
}