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

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.

Related

Unification and implicit cast of the type parameter

class Base, and class Ext extends Base.
class B<T> with typed method foo<T>(value:T)
Why B<Base>.foo doest not accept instance of B<Ext> (implicit downcast of the type parameter?) by default?
Here is an example
http://try.haxe.org/#d443f
class Test {
static function main() {
var bExt = new B(new Ext());
var bBase = new B(new Base());
bBase.foo(bExt);
//ofc
//bBase.foo(cast bExt);
}
}
class B<T>
{
public function new(v:T)
{
}
public function foo(v:B<T>)
{
//
}
}
class Base {
public function new(){}
}
class Ext extends Base {
public function new(){
super();
}
}
Is there any way to trigger implicit cast of the type parameter for B.foo?
There are three ways to interpret and answer your question:
1. foo(v:B<T>):
This is your example and it doesn't compile because T isn't allowed to be be variant. It happens because of the very existence of foo and because allowing bBase.foo(bExt), that is, unifying bExt with bBase, will then allow bBaseOfbExt.foo(bBase).
It is the fact that foo exists and that it can potentially modify the type that makes the bExt unification with bBase unsafe; you can see a similar (but maybe clearer) explanation in the manual, using arrays: type system – variance.
2. foo(v:T):
This is closer to what's on the body of your question (but not in the example) and it works fine.
3. foo<A>(v:B<A>):
Finally, if you have a type parameterized method, it also works, but you'd probably face other variance issues elsewhere.

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.

How do I call a method of an attribute derived from a generic interface, where the specific type is not known?

Core Question:
I have a generic interface IValidatingAttribute<T>, which creates the contract bool IsValid(T value); The interface is implemented by a variety of Attributes, which all serve the purpose of determining if the current value of said Field or Property they decorate is valid per the interface spec that I'm dealing with. What I want to do is create a single validation method that will scan every field and property of the given model, and if that field or property has any attributes that implement IValidatingAttribute<T>, it should validate the value against each of those attributes. So, using reflection I have the sets of fields and properties, and within those sets I can get the list of attributes. How can I determine which attributes implement IValidatingAttribute and then call IsValid(T value)?
background:
I am working on a library project that will be used to develop a range of later projects against the interface for a common third party system. (BL Server, for those interested)
BL Server has a wide range of fairly arcane command structures that have varying validation requirements per command and parameter, and then it costs per transaction to call these commands, so one of the library requirements is to easily define the valdiation requirements at the model level to catch invalid commands before they are sent. It is also intended to aid in the development of later projects by allowing developers to catch invalid models without needing to set up the BL server connections.
Current Attempt:
Here's where I've gotten so far (IsValid is an extension method):
public interface IValidatingAttribute<T>
{
bool IsValid(T value);
}
public static bool IsValid<TObject>(this TObject sourceObject) where TObject : class, new()
{
var properties = typeof(TObject).GetProperties();
foreach (var prop in properties)
{
var attributeData = prop.GetCustomAttributesData();
foreach (var attribute in attributeData)
{
var attrType = attribute.AttributeType;
var interfaces = attrType.GetInterfaces().Where(inf => inf.IsGenericType).ToList();
if (interfaces.Any(infc => infc.Equals(typeof(IValidatingAttribute<>))))
{
var value = prop.GetValue(sourceObject);
//At this point, I know that the current attribute implements 'IValidatingAttribute<>', but I don't know what T is in that implementation.
//Also, I don't know what data type 'value' is, as it's currently boxed as an object.
//The underlying type to value will match the expected T in IValidatingAttribute.
//What I need is something like the line below:
if (!(attribute as IValidatingAttribute<T>).IsValid(value as T)) //I know this condition doesn't work, but it's what I'm trying to do.
{
return false;
}
}
}
return true;
}
}
Example usage:
Just to better explain what I am trying to achieve:
public class SomeBLRequestObject
{
/// <summary>
/// Required, only allows exactly 2 alpha characters.
/// </summary>
[MinCharacterCount(2), MaxCharacterCount(2), IsRequired, AllowedCharacterSet(CharSets.Alpha))]
public string StateCode {get; set;}
}
And then, later on in code:
...
var someBLObj = SomeBLRequestObjectFactory.Create();
if(!someBLObj.IsValid())
{
throw new InvalidObjectException("someBLObj is invalid!");
}
Thank you, I'm really looking for a solution to the problem as it stands, but I'm more than willing to listen if somebody has a viable alternative approach.
I'm trying to go generic extension method with this because there are literally hundreds of the BL Server objects, and I'm going with attributes because each of these objects can have upper double digit numbers of properties, and it's going to make things much, much easier if the requirements for each object are backed in and nice and readable for the next developer to have to use this thing.
Edit
Forgot to mention : This Question is the closest I've found, but what I really need are the contents of \\Do Something in TcKs's answer.
Well, after about 6 hours and a goods nights sleep, I realized that I was over-complicating this thing. Solved it with the following (ExtValidationInfo is the class that the below two extensions are in.):
Jon Skeet's answer over here pointed me at a better approach, although it still smells a bit, this one at least works.
public static bool IsValid<TObject>(this TObject sourceObject) where TObject : class, new()
{
var baseValidationMethod = typeof(ExtValidationInfo).GetMethod("ValidateProperty", BindingFlags.Static | BindingFlags.Public);
var properties = TypeDataHandler<TObject>.Properties;
foreach (var prop in properties)
{
var attributes = prop.GetCustomAttributes(typeof(IValidatingAttribute<>)).ToList();
if (!attributes.Any())
{
continue; // No validators, skip.
}
var propType = prop.PropertyType;
var validationMethod = baseValidationMethod.MakeGenericMethod(propType);
var propIsValid = validationMethod.Invoke(null, prop.GetValue(sourceObject), attributes);
if(!propIsValid)
{
return false;
}
}
return true;
}
public static bool ValidateProperty<TPropType>(TPropType value, List<IValidatingAttribute<TPropType>> validators)
{
foreach (var validator in validators)
{
if (!validator.IsValid(value))
{
return false;
}
}
return true;
}

Using reflection how to find a class in an assembly which implements a generic base class and create its instance

I've a base presenter class:
public abstract class PresenterBase<T> where T : IView
{
//Some code
}
A concrete presenter class that implements this base:
public class RegistrationPresenter : PresenterBase<IRegistration>
{
//Some Code
}
A concrete presenter factory to return the instance of presenter which depends on a specific interface contract:
public class ProductPresenterFactory : PresenterFactoryBase
{
// Some code
public override PresenterBase<IView> GetPresenter(IView view, string name = "")
{
if (view == null && string.IsNullOrEmpty(name))
throw new ArgumentNullException();
return presenter;
}
}
I need to implement the GetPresenter method. The user will put the interface contract, for example of type IRegistration in the above case. This method should figure out the class that implements PresenterBase<IRegistration> and return an instance.
I did not write this with a compiler; I might have made a few mistakes.
You'll first need to get the type of the presenterbase, then we'll scour the assemble for the implementation, then call it's constructor. I'll make some assumptions as written in the code.
var genericType = typeof (PresenterBase<>).MakeGenericType(new[] { view.GetType() });
var allTypes = GetType().Assembly.GetTypes(); // I assume the class is in the same assembly.
var typeToImplement = allTypes.Single(t => t.IsSubclassOf(genericType)); // I assume there is only one implementation for the given type
var constructorToCall = typeToImplement.GetConstructors().First(); // I assume there is one constructor
var presenter = constructorToCall.Invoke(new object[0]); // I assume there is no parameter

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