Typescript parent reference - object

I have a recursive TS object that i'm using for building a tree.
Here is the interface definition:
export interface UIItem
{
EnumValue : myEnum;
children ?: Array<UIItem>;
expanded : boolean;
}
I need to navigate back from child to parent.
Is there a better way of doing this instead of adding the "parent" property to my interface?
export interface UIItem
{
EnumValue : myEnum;
children ?: Array<UIItem>;
parent ?: UIItem;
expanded : boolean;
}
Thank you very much in advance :)

Related

Choosing correct component type based on runtime condition

I am looking for some guidance on how best to accomplish my goal. Essentially, I want to choose the correct component type based on a runtime condition(someCondition). However, I am getting the issue below. I am sure I am overlooking something simple. I imagine I need some factory to produce the correct type(not sure why I am having trouble coming up with one 😅).
I would appreciate it if someone would explain the best way to approach this problem for future reference! Thank you in advance!
Types of construct signatures are incompatible. Type 'new <T>(props: Props<T>) => BComp<T>' is not assignable to type 'new <T>(props: Props<T>) => AComp<T>'. Construct signature return types 'BComp<T>' and 'AComp<T>' are incompatible. The types of 'getState' are incompatible between these types. Type '(s: BState) => BState' is not assignable to type '(s: AState) => AState'. Types of parameters 's' and 's' are incompatible. Property 'b' is missing in type 'AState' but required in type 'BState'.ts(2419) typescript_advance_types.ts(23, 5): 'b' is declared here.
Components:
interface Props<T> {
items: T[];
}
interface ComponentState {}
abstract class Component<T, S extends ComponentState> {
constructor(readonly props: Props<T>){}
abstract getState(s:S):S;
}
interface AState extends ComponentState {
a: boolean;
}
class AComp<T> extends Component<T, AState>{
getState(s: AState): AState {
throw new Error("Method not implemented.");
}
}
interface BState extends ComponentState {
b: boolean;
}
class BComp<T> extends Component<T, BState>{
getState(s: BState): BState {
throw new Error("Method not implemented.");
}
}
Conditionally choosing type:
let someCondition = false;
let component = AComp;
if(someCondition){
component = BComp; // issue
}
export const FinalComponent = component;

Restricting the type on function argument in Node.js and TypeScript

Working on a Node.js project and using TypeScript.
I'm trying to restrict a functions argument type to a specific base class. I'm new with both Node & TypeScript and come from a C# background, so likely not quite understanding some of the characteristics of the lang.
Take these snippets.
First, my class declarations
class DTO{
}
class userDTO extends DTO{
#IsDefined({message:"Username required"})
#Expose()
#Length(1,10, {message:"min 1 max 10"})
username:String;
}
class badDTO {
name:String;
}
Now I will create instances:
let user = new userDTO();
user.username = "My username";
let isUserDTO = user instanceof DTO; // Evaluates true
let bad = new badDTO();
bad.name = "Bob";
let isBadDTO = user instanceof DTO; // Evaluates false
Here is the signature of the method I intend to call
export default function ValidateDTO(objToValidate:DTO, validateMissingProperties:boolean): Array<string>{
return [];
}
Finally, when I actually call the function.
let userErrors = ValidateDTO(user, true);
// Why is this allowed?
let badErr = ValidateDTO(bad, true);
I am expecting the 2nd ValidateDTO to show me a warning and not actually run because 'bad' is not a DTO as proven by instanceOf above - if i try passing a string as the 2nd arg I see an error, which is what i expected from passing a non-DTO as the first arg.
Can someone please show me where I am going wrong? How can I restrict the type of object passed into a function.
Happy to share other code as required too. Not sure what else i might be missing.
You're not at all alone being surprised by this. :-) One of the key things about the TypeScript type system is that it's structural (based on structure), not nominal (based on names). As long as something has the minimum structure necessary, it matches even if it has a different ancestry. That means any object will be accepted by the type system as your DTO type because your DTO type has no properties, so all objects match it.
That's mostly a feature, but sometimes you want to disable it. The usual approach when you want to disable it is to use a branding property:
class DTO {
__brand = "DTO" as const;
}
Now, only objects that have a __brand property with the value "DTO" will be allowed where DTO objects are expected by the type system.
Here's a complete example with some minor changes to be more in keeping with JavaScript/TypeScript naming conventions and to supply some bits that were missing in the question code (presumably to keep it short! :-) ):
class DTO {
__brand = "DTO" as const;
}
class UserDTO extends DTO {
/* Commenting these out as they're not relevant to the question.
#IsDefined({message:"Username required"})
#Expose()
#Length(1,10, {message:"min 1 max 10"})
*/
username: string;
constructor(username: string) {
super();
this.username = username;
}
}
class BadDTO {
name: string = "";
}
function validateDTO(objToValidate: DTO, validateMissingProperties: boolean): string[] {
return [];
}
// Okay
validateDTO(new UserDTO("Joe"), true);
// Disallowed by the type system
validateDTO(new BadDTO(), false);
Playground link
Side note 2: In that example I added a constructor to UserDTO that initialized the username property. TypeScript has a shorthand for when you want to use a constructor paramter to initialize an instance property, this is functionally identical to the UserDTO in my example:
class UserDTO extends DTO {
/* Commenting these out as they're not relevant to the question.
#IsDefined({message:"Username required"})
#Expose()
#Length(1,10, {message:"min 1 max 10"})
*/
//−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− note no `username` declaration here
constructor(public username: string) {
// ^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− note adding `public`
super();
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− note no code here to do the
// initialization; it's implicit in the `public` declaration above
}
}
Which you use is a matter of style.

Kotlin: How to access nested object or property by var?

Is there a native way in kotlin to access a nested complex object (parsed from JSON string) through a variable?
Smth similar to:
var = "Obj4"
a = Obj1.Obj2.Obj3.$var.Obj5.Array[index]
Thanks a lot in advance
Taken from here
Using the reflection. Don't forget to add the dependency.
Global inline extension fun for Any:
inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
val getterName = "get" + propertyName.capitalize()
return try {
javaClass.getMethod(getterName).invoke(this) as? T
} catch (e: NoSuchMethodException) {
null
}
}

Casting Dynamic to an other class

I would like to know if that's possible to cast a Dynamic to an other class (partially or totally)
For example, this code breaks :
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = cast(x, Test);
}
}
with the following message
Class cast error
However, my "Test" class has an "id" field like the dynamic object. (That's an example, my use case is more complexe than that ^^)
So, I don't understand how to get an object from my Dynamic one.
This isn't exactly casting a dynamic to a class instance but may accomplish the same thing:
create an empty instance of the class with Type.createEmptyInstance
set all of the fields from the Dynamic object on the new class instance using Reflect
Example:
import haxe.Json;
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = Json.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = Type.createEmptyInstance(Test);
for (field in Type.getInstanceFields(Test))
if (Reflect.hasField(x, field))
Reflect.setProperty(t, field, Reflect.getProperty(x, field));
trace(t.id);
}
}
You could use typedef
typedef Test = {
public var id: String;
}
class Main {
public static function main() {
var t:Test = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
}
}
Json.parse returns anonymous structure(implementation platform dependent), typed as Dynamic. There isn't a single chance to cast it to anything but Dynamic, unless Json.parse returns Int, Float or String, which some parsers permit, but which isn't actually permitted by JSON specification.
That is this way because, the operation of casting doesn't check what fields some object have. Operation of casting only checks if the object is an instance of class you are casting to. Obviously, anonymous structure can't be an instance of any class(inside haxe abstractions at least).
However, the right way to perform the thing you seem to be trying to perform is the way stated by #Ben Morris, in his answer.

Type parameters - get concrete type from type T : IMyInterface

Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!

Resources