Access the getter and setter of a typescript property - properties

I have a question about typescript properties: Is it possible to get the setter and getter of a typescript property or to declare a function argument to be of a property of X type?
The reason is to get some sort of "reference" to a variable which is not possible in plain JS without writing getter/setter wrappers or access the variable via parent object itself (obj["varname"]).
For example (with some working code and other parts speculative):
//A sample class with a property
class DataClass<T> {
private T val;
public get value(): T {
return this.val;
}
public set value(value: T) {
this.val = value;
}
}
//Different ways of modifing a member "by reference"
class ModifyRef {
public static void DoSomethingByGetterAndSetter(getter: () => string, setter: (val: string) => void) {
var oldValue = getter();
setter("new value by DoSomethingByGetterAndSetter");
}
public static void DoSomethingByObject(obj: Object, name: string) {
var oldValue = obj[name];
obj[name] = "new value by DoSomethingByObject";
}
//Is something like this possible?
public static void DoSomethingByProperty(somePropery: property<string>) {
var oldVlaue = someProperty;
someProperty = "new value by DoSomethingByProperty";
}
}
var inst = new DataClass<string>();
//Calling the DoSomethingByProperty if possible
ModifyRef.DoSomethingByProperty(inst.value);
//Or if not is something like this possible
ModifyRef.DoSomethingByGetterAndSetter(inst.value.get, inst.value.set);

The simplest way to do this would be to provide methods, rather than a property:
//A sample class with a property
class DataClass<T> {
private val: T;
public getValue(): T {
return this.val;
}
public setValue(value: T) {
this.val = value;
}
}
class ModifyRef {
public static DoSomethingByGetterAndSetter(getter: () => string, setter: (val: string) => void) {
var oldValue = getter();
setter("new value by DoSomethingByGetterAndSetter");
}
}
var inst = new DataClass<string>();
//Or if not is something like this possible
ModifyRef.DoSomethingByGetterAndSetter(inst.getValue, inst.setValue);

I've long found it very surprising that languages with properties don't include a convenient way to make a reference to a property, and have daydreamed about having this feature in C#. It ought to work on local variables as well.
A popular pattern for this kind of first-class or reified property is a single function that can be called in two ways:
no arguments: returns current value.
one argument: sets value, returns undefined.
Or in TypeScript terms:
interface Property<T> {
(): T;
(newVal: T): void;
}
The methods of jQuery objects often work like this. An example of this pattern in modelling pure data is in Knockout, in which such properties also support change subscriptions, and there's a rather elegant pattern for defining computed properties that automatically recompute when their dependencies change.

Related

How to change return type based on a function input which is a class name?

I have multiple data classes and each class has a corresponding class containing more info. I want to write a function in which I should be able to pass an identifier (table name corresponding to the data class). Based on this identifier, object of the corresponding class should be made, the value changed and this object should be returned as output of the function. I have written a simplified version of it on playground but I am unable to get it to work. Any help is appreciated.
class someClass(
)
class objectForSomeClass(
var value: String
)
class someOtherClass(
)
class objectForSomeOtherClass(
var value: String
)
class doSomething() {
companion object {
val classMap = mapOf(
"someClass" to objectForSomeClass::class,
"someOtherClass" to objectForSomeOtherClass::class,
)
}
// Create a map of class name to a new object based on the class name input
fun dummyFun(className: String, valueInput: String): Map<String, kotlin.Any> {
var returnObject = mutableListOf<Pair<String, kotlin.Any>>()
when(className) {
"SOME_CLASS" -> {
returnObject = mutableListOf<Pair<String, justDoIt.classMap["someClass"]()>>()
}
"SOME_OTHER_CLASS" -> {
returnObject = Map<String, justDoIt.classMap["someOtherClass"]()>
}
}
returnObject[className].value = valueInput
return returnObject
}
}
fun main() {
var obj = doSomething()
var t = obj.dummyFun("SOME_CLASS", "Value to be inserted")
// do something with t
}
Not knowing more about your classes (the ones in your code are not data classes – a data class in Kotlin is a specific type of class) I still think a lot could be simplified down to maybe even this:
fun createObject(className: String, value: String): Any? {
return when (className) {
"SomeClass" -> ObjectForSomeClass(value)
"SomeOtherClass" -> ObjectForSomeOtherClass(value)
// ...
else -> null
}
}
Additionally:
The classMap is not necessary, you can hard-code the cases in the when clause as in my example. There is also no need for reflection, which you would need to create instances from SomeType::class.
With getting rid of classMap you also do not need the companion object holding it anymore, and then you are left with one function for creating instances of your classes, and this function does not have to be in a class. You might put it into a singleton class called object in Kotlin (https://kotlinlang.org/docs/object-declarations.html#object-expressions)
Data classes in Kotlin: https://kotlinlang.org/docs/data-classes.html
You could maybe also replace each class someClass & class objectForSomeClass pair with a class someClass with a companion object.

How to skip defined getters or setters in Kotlin

In java you can do the follwing:
public class Foo {
private String bar = "text";
public void method() {
// direct access (no logic)
System.out.println(this.bar);
}
// only if you access the object from the outside
// you are forced to use the getter with some logic in it
public String getBar() {
System.out.println(this.bar);
return this.bar;
}
}
But if you define a getter or a setter with logic in Kotlin you are forced to always execute this logic when accessing the field:
class Foo {
var bar: String = "text"
get() {
println(field)
return field
}
private set
fun method() {
// this also executes the getter
// Is it possible to skip the getter
// and directly access the field?
println(this.bar)
}
}
Is there a better way to access the field without executing the getter or setter logic than creating your own fun getBar() in Kotlin?
There is no possible way to skip a getter or a setter, they are intended to block the direct access of a property.
What you can do is make a multi-reference to same value (fake-referencing):
private var _bar: String = "text"
var bar
get() {
// some operations intercepting the getter
return _bar
}
// direct access
_bar
// intercepted access public field
bar
In Kotlin the backing fields (in your case the private variable) are not exposed by design. There are a few exceptions explained here: https://kotlinlang.org/docs/reference/properties.html#backing-fields
All access to val and var happens through implicit getters and setters. A val resolves to a property with a getter() while var resolves to a property with a getter and a setter: https://kotlinlang.org/docs/reference/properties.html#properties-and-fields

Infinite recursion in Getter in Kotlin

I am familiar with Java, but I am having difficulty working with Kotlin.
To illustrate my question, here is some Java Code. If the getter finds the field to be NULL, it initializes the field, before returning the field.
package test;
public class InitFieldJava {
private final static String SECRET = "secret";
private String mySecret;
public String getMySecret() {
if(mySecret == null) initMySecret();
return mySecret;
}
private void initMySecret() {
System.out.println("Initializing Secret ....");
mySecret = SECRET;
}
public static void main(String[] args) {
InitFieldJava field = new InitFieldJava();
System.out.println(field.getMySecret());
}
}
Can I do something like the above in Kotlin. My attempt in Kotlin looks like this:
package test
class InitFieldKotlin {
private val SECRET = "secret"
private var mySecret: String? = null
get() {
if (mySecret == null) initMySecret() //Infinite Recursion!!!
return mySecret
}
private fun initMySecret() {
println("Initializing Secret ....")
mySecret = SECRET
}
companion object {
#JvmStatic
fun main(args: Array<String>) {
val field = InitFieldKotlin()
println(field.mySecret)
}
}
}
My problem is that this results in infinite recursion:
Exception in thread "main" java.lang.StackOverflowError
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
I’d appreciate knowing what I’m doing wrong.
Try to use field keyword inside get():
private var mySecret: String? = null
get() {
if (field == null) initMySecret()
return field
}
Generally speaking, field allows to access your value directly without calling get, almost in the same way as in your Java example. More information can be found in documentation.
The problem you're facing is that when you call your property this way, the getter will be called again. And when you call getter, another getter is called, and so on until an StackOverflow.
You can fix this as shown by #Google, and using field inside the getter, instead of the property name:
if (field == null)initMySecret()
This way you won't access the property using its getter.
But more importantly: why don't you use a lazy initialization? If the variable is final, and it seems to be, you could use a lazy val
This way, the field won't be nullable anymore, so you won't have to safe-call it. And you'll not use boilerplate code, Kotlin can do this lazy initialization for you!
val mySecret: String by lazy {
println("Initializing Secret. This print will be executed only once!")
"SECRETE" //This value will be returned on further calls
}
More examples on Lazy can be seen at Kotlin Docs

Passing parameters to a custom getter in kotlin

I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}

TypeScript Interface signature for property without setter.

We have a typical getter in one of our classes, lets say
class Employee implements IEmployee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
}
and an interface to work with it
interface IEmployee{
fullName: string;
}
When working with an instance via this interface the compiler will not warn us about absence of a setter if we try to assign to fullName, and the the JS runtime simply swallows any assignment and does not throw an error. Is there any way to mark interface member as having only getter or only setter?
I've seen this post, but it is quite old, i want to know, if anything improved.
Properties in typescript can now have 'readonly' modifier, which achieves the desired restult.
interface IEmployee{
readonly fullName: string;
}
This is an interesting question. The concept of a readonly property is subtly different in TypeScript to other languages.
In many languages a property with a getter (but no setter) would raise a compiler error if you attempted to set the property, but TypeScript doesn't.
The property is still readonly, because it makes no difference if you attempt to set it; the set will fail silently.
Here is an example without any interfaces:
class Example {
get name() {
return 'Steve';
}
}
var y = new Example();
y.name = 'Example 2';
alert(y.name);
There is no compiler warning when I use x.name = 'Example 2';.
If there was a compiler warning, I would subsequently expect there to be a way of specifying the readonly-ness of a property within an interface. As you'd expect though, given the above information, you can't set a readonly property on an interface.
interface Test {
name: string;
}
class Example {
get name() {
return 'Steve';
}
}
var x: Test = new Example();
x.name = 'Example 1';
alert(x.name);
var y = new Example();
x.name = 'Example 2';
alert(x.name);
This means you can only enforce readonly-ness by having a method to get the value of the property (and obviously no method that allows it to be set).
interface Test {
getName: () => string;
}
class Example {
getName() {
return 'Steve';
}
}
var x: Test = new Example();
//x.getName('Obviously not');
//x.getName() = 'Obviously not';
alert(x.getName());
var y = new Example();
//y.getName('Obviously not');
//y.getName() = 'Obviously not';
alert(y.getName());