repropose
v1.0.2
Published
A component for building file upload fields of any type.
Downloads
3,112
Maintainers
Readme
🎲 repropose
A set of higher order functions that will, based on the given base function, create a new function decorated with additional function and instance properties ("props").
Install
npm install --save repropose
Or if you prefer yarn:
yarn add repropose
Usage
The library exposes two higher order functions: withProps
and withStaticProps
. Use them to create a new function decorated with additional function and instance properties ("props").
In the following examples, to make the code more readable, we utilize the compose
function from
the popular ramda library
(lodash also offers this).
import { compose } from "ramda";
import { withProps, withStaticProps } from "repropose";
const Vehicle = compose(
withProps(() => ({
size: "",
color: "",
weight: 0
})),
withStaticProps({
type: "vehicle"
})
)(function() {});
console.log(Vehicle.type); // "vehicle"
const vehicle = new Vehicle();
vehicle.size = "large";
vehicle.color = "red";
console.log(vehicle.size); // "large"
console.log(vehicle.color); // "red"
Both withProps
and withStaticProps
can accept an object that represents new to-be-assigned props or a function that returns it. The benefit of using a function is that it receives a reference to the new instance (withProps
) and new function (withStaticProps
) as first argument, which is useful when there's a need to check already assigned props on the previous / base function.
Note that functions created with shown HOFs are completely new functions, and are not linked in any way with the base functions.
Composing functions
It's also possible to compose existing functions with a new set of props. Although this was basically already done in the previous example (base function was an empty function), a more practical example would be composing the existing Vehicle
function with a new set of props, thus creating a new Car
function:
// All instances of Car function will be comprised of all "Vehicle"
// function's props and "doorsCount", "seatsCount" and "speed" props.
const Car = compose(
withProps({
doorsCount: 0,
seatsCount: 0,
speed: 0
})
)(Vehicle);
console.log(Vehicle.type); // "vehicle"
console.log(Car.type); // "car"
const car = new Car();
car.size = "large";
car.color = "red";
car.seatsCount = 5;
console.log(car.size); // "large"
console.log(car.color); // "red"
console.log(car.seatsCount); // 5
From here we can go even further, and define a few additional functions
that could be comprised of all Car
functions' properties and
additional specific-car-type ones. Compose as many functions as needed.
Functions as new props
Props can also be functions:
const Car = compose(
withProps({
dorsOpenedCount: 0,
openDoors(count) {
this.dorsOpenedCount = count;
}
hasOpenedDoors() {
return this.dorsOpenedCount > 0;
}
})
)(Vehicle);
const car = new Car();
console.log(car.hasOpenedDoors()); // false
car.openDoors(2);
console.log(car.dorsOpenedCount); // 2
console.log(car.hasOpenedDoors()); // true
Note: don't use arrow functions if the function is working with this
like in the above example, since it won't hold the correct object reference.
Custom HOFs
You can also create custom HOFs which you can selectively apply where needed. Consider the following example:
// We extracted the Car props into a custom HOF.
const withCarProps = () => {
return fn => {
return compose(
withProps({
doorsCount: 0,
seatsCount: 0,
speed: 0,
getSpeed() {
return this.speed;
}
})
)(fn)
}
};
// Where needed, apply "withNitro" HOF to append a piece of
// functionality to an existing function and its instances.
const withNitro = ({ nitroSpeedMultiplier }) => {
return fn => {
return compose(
withProps({
nitroEnabled: false,
enableNitro() {
this.nitroEnabled = true;
},
getSpeed() {
if (this.nitroEnabled) {
return this.speed * nitroSpeedMultiplier;
}
return this.speed;
}
})
)(fn)
}
};
const Car = compose(
withNitro({ nitroSpeedMultiplier: 2.5 }),
withCarProps()
)(Vehicle);
const car = new Car();
car.speed = 100;
console.log(car.getSpeed()); // 100
car.enableNitro();
console.log(car.nitroEnabled); // true
console.log(car.getSpeed()); // 250
You can use this idea to create a set of HOFs that are responsible for applying specific functionality and then compose them as necessary.
The motivation
This library is based on the composition over inheritance premise.
The main problem with the inheritance approach is that it forces you to define your classes / entities early in the project, which will, as new requests arrive, almost certainly result in structural inneficiencies / refactors in the future. This video describes the pros and cons of both approaches very well, so I encourage you to check it out (thanks MPJ).
🍌🦍🌴🙃
Reference
withProps(props: {[string]: any} | (newInstance : Object) => {[string]: any}): Function
Creates a new function, whose instances are decorated with given props.
withStaticProps(props: {[string]: any} | (newFunction : Function) => {[string]: any}): Function
Creates a new function, with props assigned directly to it.
Contributors
Thanks goes to these wonderful people (emoji key):
| Adrian Smijulj💻 📖 💡 👀 ⚠️ | | :---: |
This project follows the all-contributors specification. Contributions of any kind welcome!