Angular 5 prevent adding props to class - class

I have this class
export class Alpha {
propAlpha?:string;
constructor(){
}
setProp(key: string, value: string) {
this[key] = value;
}
}
Some rest call gives me an object (response) like this:
{
propAlpha: "foo",
_someUnwanted: "bar"
}
I need to push only valid props of this object into Alpha, so I did
let myAlpha = new Alpha();
_.each(Object.keys(response), key => {
validProp(response[key]) && myAlpha.setProp(key, response[key]);
/**
* validProp() checks if value matches some criteria.
* So even if "propAlpha" is in "Alpha" it may be
* excluded for some other reason!
*/
});
the problem is that _someUnwanted is added to my class.
How can I prevent that?
I'd need to check which keys are in Alpha..
maybe like this?
if(key in myAlpha) {
myAlpha.setProp(key, response[key]);
}

Different approach that doesn't require declaring separate enum is to declare class members inside it's constructor. Then your Alpha class would look like this:
export class Alpha {
constructor(public propAlpha?: string){}
setProp(key: string, value: string) {
if (key in this) this[key] = value;
}
}
assigning properties wouldn't change
_.each(Object.keys(response), key => {
validProp(response[key]) && myAlpha.setProp(key, response[key]);
});

Really awful but I solved by doing this:
export enum AlphaPublicKeys {
propAlpha
}
let myAlpha = new Alpha();
_.each(Object.keys(response), key => {
if(key in AlphaPublicKeys){
validProp(response[key]) && myAlpha.setProp(key, response[key]);
}
/**
* validProp() checks if value matches some criteria.
* So even if "propAlpha" is in "Alpha" it may be
* excluded for some other reason!
*/
});
Hope this helps!

Related

Default value for parameter of Function type in Dart

Consider a function in Dart file
void myFunction({int input = 1, Function(int, String) callback}) {
// ...
}
So, I wonder is it possible at all to specify a default value for the callback parameter, for instance it can be something like (_, _) => { }.
P.S. I know it has null as default value and ?? can help to avoid NPE, I'm just curious is it possible at all. Cheers.
You can do something like:
dynamic func(int i, String s) {
print(i.toString() + s);
}
void myFunction({int input = 1, Function(int, String) callback = func}) {
callback(input, " .");
}
void main() {
myFunction(input: 2);
}
The default value of an optional parameter must be constant.
This is what the documents said
This thing can be bypassed like this:
dynamic myCallback(int a,String b) {
}
void myFunction({int input = 1, Function(int, String) callback }) {
if (callback == null) callback = myCallback;
}
Edit:
Alternatively, you can use anonymos functaion with out myCallback funcation like this:
void myFunction({int input = 1, Function(int, String) callback }) {
if (callback == null) callback = (a,b){};
}

vscode intellisense fails in Typescript chainable method which return "instance or number", how to fix it?

Consider the following code:
class BaseType {
private _group: any = {};
private _a: number;
constructor() { }
group(g?: any): this | any {
if (!g) {
return this._group;
}
this._group = g;
return this;
}
another(a?: number): this | number {
if (Number(a) === +a) {
this._a = a;
return this;
}
return this._a;
}
}
class Another {
constructor() { }
checkChainable() {
const inst = new BaseType().group({ name: 'test' }).another(20); //The intellisense is not working here
}
}
the only why I could fix the Syntax error in the VSCode is change the return type to this | any
Is there any why I can solve the VSCode intellisense issue and compile time error?
This is caused by how union types work.
For another, the result type is either this or a number, so you can only use properties/methods on the result that are common between those two types. You'd have to do a cast or type check if you want to use properties specific to BaseType:
const x = new BaseType().another(10)
const y = typeof x === 'number' ? x : x.another(20)
You don't get an error in the group case because you are instead returning this | any which basically reduces to any, since any allows access to any properties or methods. However you won't get good intellisense for the same reason

lodash mergeWith, skip with some key

function merger(objValue, srcValue, key, object, source, stack) {
switch (key) {
case 'keya':
case 'keyb':
case 'keyc':
return null
}
}
mergeWith({}, oldObj, newObj, merger)
I would like to skip merging when key is equal to some value. But the output from above code will have the output as {keya: null} when newObj has keya.
Can I skip the merge so that the key is not in the output?
Simple answer: It is not possible with _.mergeWith.
You can see here https://github.com/lodash/lodash/issues/2966. You have to delete the null valued properties again with another process. Like,
_.omitBy(mergedObj, _.isNull);
This can totally be done like this:
function customMerge(destination, source, skip) {
return _.mergeWith(
destination,
source,
(objValue, srcValue, key) => {
if (srcValue === skip) {
_.unset(destination, key);
}
}
);
}
Here's an implementation of omitDeep that will omit any key/value that passes the predicate anywhere in the object structure.
function omitDeep(value, predicate = (val) => !val) {
return _.cloneDeepWith(value, makeOmittingCloneDeepCustomizer(predicate))
}
function makeOmittingCloneDeepCustomizer(predicate) {
return function omittingCloneDeepCustomizer(value, key, object, stack) {
if (_.isObject(value)) {
if (_.isArray(value)) {
return _(value).reject(predicate).map(item => _.cloneDeepWith(item, omittingCloneDeepCustomizer))
}
const clone = {}
for (const subKey of Object.keys(value)) {
if (!predicate(value[subKey])) {
clone[subKey] = _.cloneDeepWith(value[subKey], omittingCloneDeepCustomizer)
}
}
return clone
}
return undefined
}
}

TypeScript class decorator that modifies object instance

I'm making a plugin for Aurelia and need a class decorator that
adds attributes to the new object instance, and
calls an external function with the new object as an argument.
I've looked through examples, and so far I've put together ("pseudo-ish" code)
return function addAndCall(target: any): any {
var original = target;
var newConstructor = function (...args) {
original.apply(this, args);
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
};
newConstructor.prototype = Object.create(original.prototype);
newConstructor.prototype.constructor = original;
return <any>newConstructor;
}
but
I'm not entirely clear on the details here (or what is actually needed), and
it might not work properly since I'm getting Aurelia errors when using objects instantiated from classes with this decorator (and I suspect it's my decorator rather than the Aurelia framework that's buggy).
Any help and explanation would be greatly appreciated!
Why not just assign those properties to the prototype, and subsequently assign to the instance on first invocation
// decorator
function addAndCall(cb: Function, newField: string) {
// cb is now available in the decorator
return function(ctor: Function): void {
Object.defineProperty(ctor.prototype, newField, {
value: function(...args: any[]) {
return Object.defineProperty(this, newField, {
value: function(...args: any[]) {
console.log(newField, ...args);
}
})[newField](...args);
}
});
cb(ctor);
}
}
let callMe = (decoratedCtor) => console.log(decoratedCtor);
#addAndCall(callMe, 'propertyName')
class AddToMe {}
let addToMe = new AddToMe();
(<any>addToMe).propertyName(1, 2);
Here's a working version:
function addAndCall(target: any) {
var original = target;
function construct(constructor, args) {
var c: any = function () {
this.newAttribute = "object instance value";
ExternalModule.externalFunction(this);
return constructor.apply(this, args);;
}
c.prototype = constructor.prototype;
return new c();
}
var f: any = function (...args) {
return construct(original, args);
}
f.prototype = original.prototype;
return f;
}
(code in playground)

Autofac: Resolving contructor parameters based on single dependency

I have a scenario which I want autofac to resolve:
Here are my classes, I would have a factory method to take NetworkCredentials and return TopLevel object, this should internally resolve the InnerType1 and InnerType2 with the NetwokCredentials
public class TopLevel
{
public TopLevel(InnerType1 type1, InnerType2 type2)
{
}
}
public class InnerType1
{
public InnerType1(NetworkCredential credential)
{
}
}
public class InnerType2
{
public InnerType2(NetworkCredential credential)
{
}
}
Registration code > would something like this work ?
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => context.Resolve<TopLevel>(new TypedParameter(typeof(NetworkCredential), cred));
});
The crude approach could be to do resolve each contructor argument one by one inside resolution of TopLevel
No, that will not work since you are now instructing Autofac to provide a parameter value of type NetworkCredential to the TopLevel constructor which clearly requires two parameters of totally different types.
You will have to resolve InnerType1 and InnerType2 instances first and provide these to the TopLevel resolve. Something like this:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var context = c.Resolve<IComponentContext>();
return (cred) => {
var i1 = context.Resolve<InnerType1>(TypedParameter.From(cred));
var i2 = context.Resolve<InnerType2>(TypedParameter.From(cred));
return context.Resolve<TopLevel>(TypedParameter.From(i1), TypedParameter.From(i2));
};
});
Note: I'm not seeing the whole picture of your system here, but if you feel that this is crude, perhaps you should look at revising your class hierarchy. IMO there's a faint smell of "too complex" in your code here, you require two different classes to be configured with the same data which makes me want to de-duplicate :)
Similar to Peter's answer, but slightly different flavor:
builder.Register<Func<NetworkCredential, TopLevel>>(c =>
{
var resolveInnerType1 = c.Resolve<Func<NetworkCredential, InnerType1>>();
var resolveInnerType2 = c.Resolve<Func<NetworkCredential, InnerType2>>();
var resolveTopLevel = c.Resolve<Func<InnerType1, InnerType2, TopLevel>>();
return (cred) => {
var i1 = resolveInnerType1(cred);
var i2 = resolveInnerType2(cred);
return resolveTopLevel(i1, i2);
};
});