Is there a better way to make setter non primitive user defined type property? - typescript2.0

Hi I am new to typescript. I summarized my use case in the following example.
class Movie {
private crew: Crew;
private cast: Cast;
private locations: Location;
private movieId;
constructor(public id: string) {
this.movieId = id;
}
public getMovieId() {
return this.moveId;
}
public setCrew(value: Crew){
this.crew = value;
}
public getCrew() {
return this.crew;
}
...
//other getter and setters.
};
type Crew = {
crew_varA: string,
crew_varB: boolean,
crew_varC: string,
crew_varD: boolean,
}
type Cast = {
cast_varE: string,
cast_varF: string,
cast_varG: string,
}
type Location = {
loc_varX: string,
loc_varY: string,
loc_varZ: string,
}
when I create an object of Movie, I need to call setCrew() method. But only 'crew_varA' variable has value by that time. I am not able to make a call to setCrew() method with only one variable. I need to initialize all variables with some default value which is not appropriate something like this.
let mv = new Movie("SpiderMan");
mv.setCrew({crew_varA: "Peter Parker", crew_varB:false, crew_varC:null, crew_varD:null}; //is there a way to set only one property of Crew and add other properties one by one based on some logic??
I am not sure my approach is correct or not. I appreciate your help.

Related

How to establish getter & setter for secondary constructor in data class for kotlin?

I need a data class with two different constructors as shown. But how do I do getter & setter for the secondary constructor of data class in Kotlin? I tried multiple changes, not able to figure it out. In the below snippet, I am not getting the right import for get() and set()
data class user(var phone: String) {
constructor(phone: String, name : String) : this(phone) {
var name: String = name
get()= field
set(value) {
field = value
}
}
}
It appears you want two constructors, one which only requires a "phone" argument and another which requires both a "phone" and "name" argument. Overall, your data class will have two properties regardless of which constructor is used: phone and name. You could accomplish this with the following:
data class User(var phone: String) {
var name: String = ""
constructor(phone: String, name: String) : this(phone) {
this.name = name
}
}
However, as this is Kotlin, you should prefer default parameter values over overloaded functions/secondary constructors:
data class User(var phone: String, var name: String = "")

`java.lang.StackOverflowError` when accessing Kotlin property

I got this (contrived) sample from Packt's "Programming Kotlin" on using secondary constructor with inheritance.
Edit: from the answer it is clear that the issue is about backing field. But the book did not introduced that idea, just with the wrong example.
open class Payment(val amount: Int)
class ChequePayment : Payment {
constructor(amount: Int, name: String, bankId: String) : super(amount) {
this.name = name
this.bankId = bankId
}
var name: String
get() = this.name
var bankId: String
get() = this.bankId
}
val c = ChequePayment(3, "me", "ABC")
println("${c} ${c.amount} ${c.name}")
When I run it this error is shown.
$ kotlinc -script class.kts 2>&1 | more
java.lang.StackOverflowError
at Class$ChequePayment.getName(class.kts:10)
at Class$ChequePayment.getName(class.kts:10)
at Class$ChequePayment.getName(class.kts:10)
Line 10 does seems to be a infinite recursion, how to solve it?
You have a recursion in your code:
class ChequePayment : Payment {
constructor(amount: Int, name: String, bankId: String) : super(amount) {
this.name = name
this.bankId = bankId
}
var name: String
get() = this.name // recursion: will invoke getter of name (itself)
var bankId: String
get() = this.bankId // recursion: will invoke getter of bankId (itself)
}
If you don't need custom logic for your getter, just leave your properties like this:
var name: String
var bankId: String
They will have a default getter, which does nothing more than returning the value of the backing field.
Note: The code as it is can/should be refactored to this:
class ChequePayment(amount: Int, var name: String, var bankId: String) : Payment(amount) {
// ...
}
This uses the primary constructor and is much less redundant.
To access the backing field you have to use the keyword field instead of this.name see https://kotlinlang.org/docs/reference/properties.html#backing-fields
this.name references the getter, which references this.name which is an infinite recursion, as you already noted. In code:
var name: String
get() = field
var bankId: String
get() = field
Side note: Android Studio and Idea will complain rightfully that you don't need a getter in this case. So you can simplify even more:
var name: String
var bankId: String

Convert enum member to corresponding text

In Kotlin I have an enum as follows:
enum class MediaType() {
AUDIO,
VIDEO,
ARTICLE;
}
I would like to add either a function or some property that allows an enum member to be converted to some corresponding text. For example:
var mediaType = MediaType.AUDIO
var text = mediaType.toText() // returns the string "MP3"
mediaType = MediaType.VIDEO
text = mediaType.toText() // returns the string "mpeg"
While I can add the toText function to the MediaType class, I am not sure how that function references the value it is set to.
You can add a property to the enum...
enum class MediaType(val text: String) {
AUDIO("mp3"),
VIDEO("mpeg"),
ARTICLE("text");
}
And then use it like this:
println(MediaType.AUDIO.text)
If you'd like a toText() function rather than a property, that can be added as well, but probably isn't as idiomatic:
enum class MediaType(private val text: String) {
AUDIO("mp3"),
VIDEO("mpeg"),
ARTICLE("text");
fun toText(): String = text
}
Update:
Another way is to add an extension function and keep this logic outside the enum entirely:
fun MediaType.toText(): String =
when(this) {
MediaType.AUDIO -> "mp3"
MediaType.VIDEO -> "mpeg"
MediaType.ARTICLE -> "text"
}
enum class MediaType() {
AUDIO,
VIDEO,
ARTICLE;
fun getMemberText() = when (this) {
AUDIO -> "mp3"
VIDEO -> "mpeg"
else -> "text"
}
}

Implementing properties declared in interfaces in Kotlin

I'm new to Kotlin, so I have this interface.
interface User {
var nickName : String
}
Now I want to create a class PrivateUser that implements this interface. I have also to implement the abstract member nickName.
Via constructor it's very simple
class PrivateUser(override var nickName: String) : User
However when I try to implement member inside the class Idea generates me this code
class Button: User {
override var nickName: String
get() = TODO("not implemented")
set(value) {}
}
It's confusing to me how to implement it further.
Properties must be initialized in Kotlin. When you declare the property in the constructor, it gets initialized with whatever you pass in. If you declare it in the body, you need to define it yourself, either with a default value, or parsed from other properties.
Some examples:
class Button : User {
override var nickname = "Fred"
}
class Button(val firstName: String, val lastName: String) : User {
override var nickname = "${firstname[0]}$lastname"
}
The code generated by IDEA is useful if you want a non-default getter and/or setter, or if you want a property without a backing field (it's getter and setter calculate on the fly when accessed).
More examples:
class Button : User {
override var nickname = "Fred"
get() = if (field.isEmpty()) "N/A" else field
set(value) {
// No Tommy
field = if (value == "Tommy") "" else value
}
}
class Button(val number: Int) : User {
var id = "$number"
private set
override var nickname: String
get() {
val parts = id.split('-')
return if (parts.size > 1) parts[0] else ""
}
set(value) {
field = if (value.isEmpty()) "$number" else "$value-$number"
}
}

Access the getter and setter of a typescript property

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.