I have a function like so:
const ILog = <T>(value: T): T => {
console.log(value);
return value;
}
It acts like console.log with the added benefit that it keeps the value it had.
However, I'd like to differenciate between calls of the same function:
let a = false;
let b = false;
let c = false;
ILog(a);
ILog(b);
ILog(c);
// current
$ node file.js
false
false
false
// expected
$ node file.js
ILog(a): false
ILog(b): false
ILog(c): false
Can some javascript black magic achieve this?
An example of how this would work would be like this:
const ILog = (name: string) => <T>(value: T): T => {
console.log(`ILog(${name})`, value);
return value;
}
ILog("[some_expression]")([some_expression]);
$ node file.js
ILog([some_expression]): [result]
Without repeating the expression in string form.
There's no magic way to do this, you could do something like this if you really wanted:
const ILog = <T>(value: T, argumentName: string): T => {
console.log(`ILog(${argumentName}): ${value}`);
return value;
}
const a = false;
ILog(a, "a");
Or using your existing ILog function,
ILog(`ILog(a): ${a}`);
Related
Code Snippet:
let myMath = new AntraMath(10);
myMath.add(5);
myMath.multiply(2);
let res = myMath.done();
console.log(res);
Constructor Function Attempt:
function AntraMath (_value){
let myMath = new AntraMath(10);
myMath.add(5);
myMath.multiply(2);
let res = myMath.done();
console.log(res);
}
I tried to create a Constructor function "AntraMath" & follow along with the errors given afterwards. But after setting up; I received "Output: [Done] exited with code=0" instead of receiving any error's or the desired output 30.
Thank you to who ever may be reading this along with any input given.
You will need to define a class (or prototype) and use it. Your code contains usage, but does not contain the definitions you need.
class AntraMath {
constructor(_value) {
this._value = _value;
}
add(_value) {
this._value += _value;
return this;
}
multiply(_value) {
this._value *= _value;
return this;
}
done() {
return this._value;
}
}
let myMath = new AntraMath(10);
myMath.add(5);
myMath.multiply(2);
let res = myMath.done();
console.log(res);
I have an object and I need to modify some of its attributes. For this I'm using custom commands and the first one modifies a couple of them when the second modifies only one but I execute the second custom command from the first one. When I execute my test, the attribute modified by the second command is null.
How can I do this?
Here's a sample of how my code looks:
Cypress.Commands.add("firstCommand", (varA, objectB) => {
let aBody = {};
aBody.a = varA;
cy.modifiesOtherAttr(aBody, objectB);
})
Cypress.Commands.add("modifiesOtherAttr", (aBody, objectB) => {
aBody.b = objectB.attrb;
})
Then my test only calls the first command
describe("a suite name", () => {
it("my test name", () => {
cy.firstCommand(variable, object);
})
})
Ideally you want to be specific about the return value from each custom command.
However, Cypress will pick up the last command inside the custom command and return it's subject. But within firstCommand the last command is modifiesOtherAttr which does not have a return value or any cy command, so Cypress returns undefined which is then what firstCommand returns.
Since you create a new object aBody, it should be explicitly returned.
Cypress.Commands.add("firstCommand", (varA, objectB) => {
let aBody = {};
aBody.a = varA;
cy.modifiesOtherAttr(aBody, objectB)
cy.wrap(aBody) // this is the return value
});
Cypress.Commands.add("modifiesOtherAttr", (aBody, objectB) => {
aBody.b = objectB.attrb // "side effect" happens here, nothing returned
});
OR
Cypress.Commands.add("firstCommand", (varA, objectB) => {
let aBody = {};
aBody.a = varA;
cy.modifiesOtherAttr(aBody, objectB) // this is the return value
});
Cypress.Commands.add("modifiesOtherAttr", (aBody, objectB) => {
aBody.b = objectB.attrb
cy.wrap(aBody) // this is the return value
});
Explicit is better
Cypress.Commands.add("firstCommand", (varA, objectB) => {
let aBody = {};
aBody.a = varA;
cy.modifiesOtherAttr(aBody, objectB)
return cy.wrap(aBody) // this is the return value
});
Cypress.Commands.add("modifiesOtherAttr", (aBody, objectB) => {
aBody.b = objectB.attrb
return cy.wrap(aBody) // this is the return value
});
Is there a way to shorten this fragment of code?
const result = getResult();
if (!result) {
return;
}
// Work with result
I keep having lots of these in my code and would love to do something like:
const result = getResult() || return;
// Work with result
EDIT:
I only want convertable inputs to be persisted.
const parseInput = (input: string): void => {
const convertedInput = convert(input);
if (!convertedInput) {
return;
}
persist(convertedInput);
}
I know I could call the converter twice. But I want to avoid that:
const parseInput = (input: string): void => {
if (!convert(input)) {
return;
}
persist(convert(input));
}
Your code is as good as it gets, however, if you want to experiment a bit with the functional style, you can wrap the value into a "monad", which would invoke attached functions only if the value is non-zero. Here's a toy implementation:
function maybe(x) {
return {
value: x,
apply(fn) {
if (this.value)
this.value = fn(this.value)
return this;
}
}
}
With this maybe, your example would look like:
const parseInput = input => maybe(convert(input)).apply(persist)
See the Oliver's answer for a more serious approach.
You can do this
const result = "default value" || getResult();
If getResult is null or not defined then you'll get result as "default value". If that's what you want
function getResult() {
return null;
}
const result = "okay" || getResult();
console.log(result)
And when getResult is not defined you get
const result = "okay" || getResult();
console.log(result)
Basically, the syntax is
null || undefined || null || 0 || "okay" || "defined" // "okay"
It goes from left to right and picks the most relevant value
I don't really know if this answer will give you something that you'll be happy with, but it seems to me to present a potential solution to the problem of handling unknown results.
Maybes are structures which have this kind of checking built-in. the .map() below will not be called if there is no value in the Maybe, so the code which consumes it does not need to check whether a value is present.
This does mean that you have to change the way in which you handle these values however, and, unless you want to write your own, it means using a library. As such this is hardly an ideal solution, but I hope it gives an option at least.
const { None, Some } = Monet;
const getResult = () => Math.random() > 0.5
? None()
: Some(1);
const test = getResult()
.map(x => x + 2);
console.dir(test.val);
<script src="https://cdn.jsdelivr.net/npm/monet#0.9.0/dist/monet.min.js"></script>
I'm wondering if there's a concise or specific way to access values in the middle of an FP chain in JavaScript. Example:
const somestuff = [true, true, false];
let filteredCount = 0;
somestuff.filter((val) => val)
.forEach((val) => console.log(val));
Above, I'd like to set filteredCount to the length of the array returned by the filter function. The most straight-forward way is:
const somestuff = [true, true, false];
const filteredStuff = somestuff.filter((val) => val);
let filteredCount = filteredStuff.length;
filteredStuff.forEach((val) => console.log(val));
This is certainly valid but it breaks our FP chain and introduces an additional holding variable. I'm wondering if there's a convention for accessing values in the middle of the chain. Something like .once() that runs once and implicitly returns the value passed in, but nothing like that exists.
For debugging, I often use a function called tap to temporarily add a side-effect (like your console.log) to a function:
const tap = f => x => (f(x), x);
This function returns whatever it is passed, but not before calling another function with the value. For example:
const tap = f => x => (f(x), x);
const tapLog = tap(console.log);
const x = tapLog(10);
console.log("x is", x);
Your snippet basically does this:
Filter a list
(log the list)
Retrieve a length property from an array
If you construct this function using pipe or compose, you can "inject" the console.log in between without interrupting the data flow:
const countTrues = pipe(
filter(isTrue),
prop("length")
);
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
In a snippet:
// Utils
const isTrue = x => x === true;
const prop = k => obj => obj[k];
const tap = f => x => (f(x), x);
const filter = f => xs => xs.filter(f);
const pipe = (...fns) => x => fns.reduce((res, f) => f(res), x);
// Logic:
// Filter an array using the isTrue function
// and return the length of the result
const countTrues = pipe(
filter(isTrue),
prop("length")
);
// Create a filter with a console.log side-effect
// and return the length of the result
const countTruesWithLog = pipe(
filter(isTrue),
tap(console.log),
prop("length")
);
// App:
const somestuff = [true, true, false];
console.log("pure:");
const countA = countTrues(somestuff)
console.log(countA);
console.log("with log:")
const countB = countTruesWithLog(somestuff);
console.log(countB);
The reason there's no Array.prototype method like that, is that it has a side effect. This is something that is specifically avoided in functional programming.
However if you don't care about writing 'Pure Functions', or even the functional paradigm, you could put the side effect in your callbacks, or write a function in the Array prototype.
ie.
Array.prototype.once = function(callback) {
callback(this)
return this
}
You also have other hacky options like in the other answer
I don't think there's something like that by default. What you can do is extend Array, but I'm not really fond of extending framework classes (clashes with other once implementations for example). In this case you'd end up with:
Array.prototype.once = function once(func) {
func(this);
return this;
}
which is called like:
var filteredStuff = somestuff
.filter((val) => val)
.once(function(array) {
console.log(array.length);
})
.forEach((val) => console.log(val));
On the other hand, you can try to use default functions. One of these function that can access all items at once is reduce. Define a function once, that will call its first parameter once (:)) and you'd end up with something like:
function once(func) {
return function(accumulator, currentValue, currentIndex, array) {
if(currentIndex === 1) {
func(array);
}
return array;
}
}
which you'd be able to call like this:
var filteredStuff = somestuff
.filter((val) => val)
.reduce(once(function(array) {
console.log(array.length);
}), [0])
.forEach((val) => console.log(val));
Notice the ugly [0] to ensure once calls the passed function at least once (empty array included).
Both solutions aren't too neat, but it's the best I can come up with given the criteria.
After reading the Jest documentation, when it's mentioned that to export a single function from a tested file they show the following example:
function sum(a, b) {
return a + b;
}
module.exports = sum;
Now, if I have multiple specific functions I want to export on my tested file, like this:
function sum(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function subtract(a, b) {
return a - b;
}
module.exports = sum;
module.exports = multiply;
The multiply function is the only one being exported. How can I make these function be exported? Or only part of my file?
You can do something like this :
module.exports = {};
module.exports.sum = function sum(a, b) {
return a + b;
}
module.exports.multiply = function multiply(a, b) {
return a * b;
}
module.exports.subtract = function subtract(a, b) {
return a - b;
}
End you use it like this:
var MyMathModule = require('./my_math_module');
MyMathModule.sum(a, b);
MyMathModule.multiply(a, b);
MyMathModule.subtract(a, b);
First, in your example, all you are doing there is overriding the exports object with a function ( which is totally fine )
The exports and module.exports are an object and are actually the same object ( i.e. module.exports === exports // true )
To do what you want you can do this a couple ways:
exports.sum = sum
exports.multiply = multiply
or
module.exports = { sum: sum, multiply: multiply } // etc
or
module.exports.sum = sum
module.exports.multiply = multiply
Having in mind the answer to this question, i'll paste here 2 ways to do the same thing.
For example, you have the JS file called exercise5, like this:
//You can create an object with functions, as follows:
const wordAnalysis = {
type: (word) => typeof (word),
whiteSpaces: (word) => {
let wordAnalysis = word.includes(' ')
if (wordAnalysis) {
return 'It has spaces'
} else {
return "It doesn't has spaces"
}
}
}
//Or you can create several single functions, like the following:
function numberAnalysis(word) {
let isANumber = typeof (word) === 'number' ? true : false
return isANumber
}
// în order to avoid overwriting the module.exports, it is needed to do one of the following (I chose the first one):
// 1)
module.exports.firstPlace = wordAnalysis
module.exports.secondPlace = numberAnalysis
// 2)
// module.exports = {
// functions: functions,
// isANumber: isANumber
// }
// 3)
// exports.functions = functions
// exports.isANumber = isANumber
// 4)
// exports = {
// functions: functions,
// isANumber: isANumber
// }
Now the file test named exercise5.test.js:
const wordAnalysis = require('./exercise5')
const numberAnalysis = require('./exercise5')
test('It should give me the type of what was typed', () => {
expect(wordAnalysis.firstPlace.type('teste')).toEqual('string')
})
test('It should give me the type of what was typed', () => {
expect(wordAnalysis.firstPlace.type(22)).toEqual('number')
})
test("It should give true if what is typed has at least a space or false if it doesn't", () => {
expect(wordAnalysis.firstPlace.whiteSpaces('Jon is cool')).toEqual('It has spaces');
})
test("It should give true if what is typed has at least a space or false if it doesn't", () => {
expect(wordAnalysis.firstPlace.whiteSpaces('AllTogetherNow')).toBe("It doesn't has spaces");
})
test('it should analyse if the given expression is a number or not', () => {
expect(numberAnalysis.secondPlace(2)).toBeTruthy()
})
test('it should analyse if the given expression is a number or not', () => {
expect(numberAnalysis.secondPlace('jon')).toBeFalsy()
})
The only thing you need to be aware is to export/import the correct object/function, and of course call it when your are developing the test.