pure-assign
Advanced tools
Comparing version 0.1.4 to 1.0.0
/** | ||
* Drop-in replacement for `Object.assign()` for "updating" immutable objects. Unlike | ||
* `Object.assign()`, `pureAssign()` will not create a new object if no properties change. | ||
* Drop-in replacement for `Object.assign()` for "updating" immutable objects. | ||
* Unlike `Object.assign()`, `pureAssign()` will not create a new object if no | ||
* properties change. | ||
* | ||
* @param baseObject An object which serves as the basis for the updated values. | ||
* @param updates One or more objects whose values should replace the corresponding values | ||
* in `baseObject`. Values in rightward objects take precedence over those in earlier ones. | ||
* @returns An object whose keys and values match those of `baseObject` except where they have been | ||
* overridden by those of `updates`. The input objects are unchanged. If the returned | ||
* object would be identical to `baseObject`, then `baseObject` is returned. | ||
* @param updates One or more objects whose values should replace the | ||
* corresponding values in `baseObject`. Values in rightward objects take | ||
* precedence over those in earlier ones. | ||
* @returns An object whose keys and values match those of `baseObject` except | ||
* where they have been overridden by those of `updates`. The input | ||
* objects are unchanged. If the returned object would be identical to | ||
* `baseObject`, then `baseObject` is returned. | ||
*/ | ||
export default function pureAssign<T, K extends keyof T>(baseObject: T, update: Pick<T, K>): T; | ||
export default function pureAssign<T>(baseObject: T, ...updates: Array<Partial<T>>): T; |
@@ -1,14 +0,2 @@ | ||
"use strict"; | ||
/** | ||
* Drop-in replacement for `Object.assign()` for "updating" immutable objects. Unlike | ||
* `Object.assign()`, `pureAssign()` will not create a new object if no properties change. | ||
* | ||
* @param baseObject An object which serves as the basis for the updated values. | ||
* @param updates One or more objects whose values should replace the corresponding values | ||
* in `baseObject`. Values in rightward objects take precedence over those in earlier ones. | ||
* @returns An object whose keys and values match those of `baseObject` except where they have been | ||
* overridden by those of `updates`. The input objects are unchanged. If the returned | ||
* object would be identical to `baseObject`, then `baseObject` is returned. | ||
*/ | ||
function pureAssign(baseObject) { | ||
export default function pureAssign(baseObject) { | ||
var updates = []; | ||
@@ -28,9 +16,6 @@ for (var _i = 1; _i < arguments.length; _i++) { | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = pureAssign; | ||
function simplePureAssign(baseObject, update) { | ||
for (var key in update) { | ||
if (Object.prototype.hasOwnProperty.call(update, key) | ||
&& (!(key in baseObject) | ||
|| baseObject[key] !== update[key])) { | ||
if (Object.prototype.hasOwnProperty.call(update, key) && | ||
(!(key in baseObject) || baseObject[key] !== update[key])) { | ||
return assign({}, baseObject, update); | ||
@@ -41,13 +26,17 @@ } | ||
} | ||
var assign = Object.assign || function (t) { | ||
for (var s = void 0, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) { | ||
if (Object.prototype.hasOwnProperty.call(s, p)) { | ||
t[p] = s[p]; | ||
// We need a non-arrow function to use the arguments array. | ||
// tslint:disable:only-arrow-functions | ||
var assign = Object.assign || | ||
function (t) { | ||
for (var s = void 0, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) { | ||
if (Object.prototype.hasOwnProperty.call(s, p)) { | ||
t[p] = s[p]; | ||
} | ||
} | ||
} | ||
} | ||
return t; | ||
}; | ||
return t; | ||
}; | ||
// tslint:enable:only-arrow-functions | ||
//# sourceMappingURL=index.js.map |
117
package.json
{ | ||
"name": "pure-assign", | ||
"version": "0.1.4", | ||
"description": "Drop-in replacement for Object.assign() for \"updating\" immutable objects.", | ||
"main": "dist/index.js", | ||
"types": "dist/index", | ||
"files": [ | ||
"dist/" | ||
], | ||
"scripts": { | ||
"clean": "rm -rf dist", | ||
"build": "npm run clean && tsc", | ||
"jest": "jest", | ||
"jest-watch": "npm run jest -- --watch", | ||
"lint": "tslint --project .", | ||
"prepublish": "npm run build", | ||
"test": "npm run lint && npm run jest", | ||
"watch": "npm run clean && tsc --watch" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/dphilipson/pure-assign.git" | ||
}, | ||
"keywords": [ | ||
"object", | ||
"assign", | ||
"immutable", | ||
"update" | ||
], | ||
"author": "David Philipson <dphilipson@gmail.com> (http://dphil.me)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/dphilipson/pure-assign/issues" | ||
}, | ||
"homepage": "https://github.com/dphilipson/pure-assign#readme", | ||
"devDependencies": { | ||
"@types/jest": "^16.0.3", | ||
"jest": "^18.1.0", | ||
"ts-jest": "^18.0.1", | ||
"tslint": "4.1.0", | ||
"typescript": "^2.1.4" | ||
}, | ||
"jest": { | ||
"transform": { | ||
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js" | ||
"name": "pure-assign", | ||
"version": "1.0.0", | ||
"description": "Drop-in replacement for Object.assign() for \"updating\" immutable objects.", | ||
"main": "dist/index.js", | ||
"types": "dist/index", | ||
"files": [ | ||
"dist/" | ||
], | ||
"sideEffects": false, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/dphilipson/pure-assign.git" | ||
}, | ||
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js" | ||
] | ||
} | ||
"keywords": [ | ||
"transducers", | ||
"typescript", | ||
"functional", | ||
"iterators", | ||
"lazy", | ||
"chain" | ||
], | ||
"homepage": "https://github.com/dphilipson/pure-assign", | ||
"bugs": { | ||
"url": "https://github.com/dphilipson/pure-assign/issues", | ||
"email": "david.philipson@gmail.com" | ||
}, | ||
"author": "David Philipson <david.philipson@gmail.com> (http://dphil.me)", | ||
"license": "MIT", | ||
"scripts": { | ||
"build": "yarn run clean && tsc -p tsconfig.build.json", | ||
"clean": "rm -rf dist/*", | ||
"format-file": "prettier --write", | ||
"format": "git ls-files | egrep '\\.(js(on)?|md|scss|tsx?)?$' | xargs yarn run format-file", | ||
"jest": "jest", | ||
"lint-file": "tslint", | ||
"lint": "tslint --project .", | ||
"prepublishOnly": "yarn run test && yarn run build", | ||
"test": "yarn run lint && tsc && yarn run jest" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"**/*.{js,json,md}": [ | ||
"yarn run format-file", | ||
"git add" | ||
], | ||
"**/*.ts": [ | ||
"yarn run lint-file --fix", | ||
"yarn run format-file", | ||
"git add" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.3.9", | ||
"husky": "^1.1.3", | ||
"jest": "^23.6.0", | ||
"lint-staged": "^8.0.4", | ||
"prettier": "^1.15.1", | ||
"ts-jest": "^23.10.4", | ||
"tslint": "^5.11.0", | ||
"tslint-config-prettier": "^1.15.0", | ||
"typescript": "^3.1.6" | ||
}, | ||
"dependencies": {} | ||
} |
155
README.md
# Pure Assign | ||
Drop-in replacement for | ||
[Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) | ||
for "updating" immutable objects. Unlike `Object.assign()`, `pureAssign()` will not create a new | ||
object if no properties change. | ||
[`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) | ||
for "updating" immutable objects. Unlike `Object.assign()`, `pureAssign()` will | ||
not create a new object if no properties change. | ||
[![Build Status](https://travis-ci.org/dphilipson/pure-assign.svg?branch=master)](https://travis-ci.org/dphilipson/pure-assign) | ||
[![Build | ||
Status](https://travis-ci.org/dphilipson/pure-assign.svg?branch=master)](https://travis-ci.org/dphilipson/pure-assign) | ||
## Installation | ||
With Yarn: | ||
``` | ||
npm install --save pure-assign | ||
yarn add pure-assign | ||
``` | ||
## Motivation | ||
With NPM: | ||
Many JavaScript programs treat objects as immutable data. For instance, this is recommended by | ||
React and required by Redux. Such programs typically replace object mutation: | ||
``` javascript | ||
userObject.firstName = "Anastasia"; | ||
userObject.lastName = "Steele"; | ||
``` | ||
with calls to `Object.assign()`, creating a new object with the updated values: | ||
``` javascript | ||
const updatedUserObject = Object.assign({}, userObject, { | ||
firstName: "Anastasia", | ||
lastName: "Steele" | ||
}); | ||
npm install pure-assign | ||
``` | ||
or alternatively with [ES7's spread operator](https://github.com/sebmarkbage/ecmascript-rest-spread) | ||
and an appropriate transpiler: | ||
``` javascript | ||
const updatedUserObject = { | ||
...userObject, | ||
firstName: "Anastasia", | ||
lastName: "Steele", | ||
}; | ||
``` | ||
A drawback of this approach is that a new object is created even if the new properties are identical | ||
to the old ones. Beyond the minor performance impact, this can have greater consequences if certain | ||
updates are triggered by data "changes." For example, React developers may attempt to avoid | ||
unnecessary re-renders by using | ||
[PureComponent](https://facebook.github.io/react/docs/react-api.html#react.purecomponent), which | ||
only performs an update if its props have "changed" according to a shallow-equality check. This | ||
means that if your updates create new objects with the same values, they will trigger unnecessary | ||
re-renders since the old props do not have object-equality with the new props, despite having the | ||
same values. | ||
This is where `pureAssign()` comes in. `pureAssign(object, updates)` is equivalent to | ||
`Object.assign({}, object, updates)`, but will return the original object if nothing would be | ||
changed. For instance: | ||
``` javascript | ||
## Usage | ||
`pureAssign()` takes one or more arguments. The first argument is a base object, | ||
and the remaining arguments are any number of objects whose properties should be | ||
merged with those of the base object to produce a new object. Unlike | ||
[`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign), | ||
the first argument is not modified. For example: | ||
```ts | ||
import pureAssign from "pure-assign"; | ||
const userObject = { firstName: "Anastasia", lastName: "Steele" }; | ||
const updatedUserObject = pureAssign(userObject, { firstName: "Anastasia" }); | ||
console.log(userObject === updatedUserObject); // true | ||
const user = { firstName: "Anastasia", lastName: "Steele" }; | ||
const updatedUser = pureAssign(user, { firstName: "Ana" }); | ||
console.log(user); // -> { firstName: "Anastasia", lastName: "Steele" } | ||
console.log(updatedUser); // -> { firstName: "Ana", lastName: "Steele" } | ||
``` | ||
Note that unlike `Object.assign()`, the first argument of `{}` is absent. | ||
Like `Object.assign()`, multiple update arguments may be given, where values found in later objects | ||
take precedence over earlier ones. A new object is returned only if the final result of applying | ||
all updates has different values from the original object. For example: | ||
``` javascript | ||
import pureAssign from "pure-assign"; | ||
If the resulting object would differ from the original, then a new object is | ||
created and returned. Otherwise, the original instance is returned. For example: | ||
const userObject = { firstName: "Anastasia", lastName: "Steele" }; | ||
```ts | ||
const user = { firstName: "Anastasia", lastName: "Steele" }; | ||
const updatedUser = pureAssign(user, { firstName: "Anastasia" }); | ||
console.log(user === updatedUser); // -> true | ||
``` | ||
const updatedUserObject1 = pureAssign( | ||
userObject, | ||
{ firstName: "Christian", lastName: "Kavanagh" }, | ||
{ firstName: "Kate" } | ||
); | ||
console.log(updatedUserObject1); // { firstName: "Kate", lastName: "Kavanagh" } | ||
In other words, the following are equivalent: | ||
const updatedUserObject2 = pureAssign( | ||
userObject, | ||
{ firstName: "Ana", lastName: "Steele" }, | ||
{ firstName: "Anastasia" } | ||
); | ||
console.log(userObject === updatedObject2); // true | ||
```ts | ||
pureAssign(object, ...updates); | ||
``` | ||
For TypeScript users, `pureAssign` has an additional advantage in that it catches type errors | ||
of the following form, which would be uncaught if using `Object.assign()` or object spread: | ||
``` javascript | ||
import pureAssign from "pure-assign"; | ||
const userObject = { firstName: "Anastasia", lastName: "Steele" }; | ||
```ts | ||
Object.assign({}, object, ...updates); | ||
``` | ||
const updatedUserObject = pureAssign(userObject, { firstNarm: "Ana" }); | ||
except that when using `pureAssign` the original instance is returned if no | ||
changes would be applied. | ||
For TypeScript users, `pureAssign` has an additional advantage in that it | ||
catches type errors of the following form, which would be uncaught if using | ||
`Object.assign()` or object spread: | ||
```javascript | ||
const user = { firstName: "Anastasia", lastName: "Steele" }; | ||
const updatedUser = pureAssign(userObject, { firstNarm: "Ana" }); | ||
// Type error because "firstNarm" is not a property of userObject. | ||
``` | ||
## Motivation | ||
Many JavaScript programs treat objects as immutable data. For instance, this is | ||
recommended by React and required by Redux. Such programs typically replace | ||
object mutation: | ||
```javascript | ||
const user = { firstName: "Anastasia", lastName: "Steele" }; | ||
user.firstName = "Ana"; | ||
``` | ||
with calls to `Object.assign()`, creating a new object with the updated values: | ||
```javascript | ||
const updatedUser = Object.assign({}, user, { | ||
firstName: "Ana", | ||
}); | ||
``` | ||
or alternatively with [ES7's spread | ||
operator](https://github.com/sebmarkbage/ecmascript-rest-spread) and an | ||
appropriate transpiler: | ||
```javascript | ||
const updatedUser = { ...user, firstName: "Ana" }; | ||
``` | ||
A drawback of this approach is that a new object is created even if the new | ||
properties are identical to the old ones. This may have performance implications | ||
if certain updates are triggered by data "changes." For example, React | ||
developers may attempt to avoid unnecessary re-renders by using | ||
[`PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent) or | ||
[`React.memo()`](https://reactjs.org/docs/react-api.html#reactmemo), which only | ||
performs an update if its props have "changed" according to a shallow-equality | ||
check. This means that if your updates create new objects with the same values, | ||
they will trigger unnecessary rerenders since the old props do not have | ||
object-equality with the new props, despite being functionally identical. | ||
This is where `pureAssign()` comes in. By returning the same instance in cases | ||
where the values haven't changed, `pureAssign` avoids triggering unnecessary | ||
updates which use object-equality to determine whether the state has changed. | ||
Copyright © 2017 David Philipson |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
12895
0
117
9
55