-
Notifications
You must be signed in to change notification settings - Fork 358
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(propertyOf): Add
propertyOf
to compat (#884)
- Loading branch information
Showing
8 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { bench, describe } from 'vitest'; | ||
import { propertyOf as propertyOfToolkit_ } from 'es-toolkit/compat'; | ||
import { propertyOf as propertyOfLodash_ } from 'lodash'; | ||
|
||
const propertyOfToolkit = propertyOfToolkit_; | ||
const propertyOfLodash = propertyOfLodash_; | ||
|
||
describe('propertyOf', () => { | ||
bench('es-toolkit/propertyOf', () => { | ||
const getValue = propertyOfToolkit({ 'a.b': 1, a: { b: 1 } }); | ||
getValue('a.b'); | ||
}); | ||
|
||
bench('lodash/propertyOf', () => { | ||
const getValue = propertyOfLodash({ 'a.b': 1, a: { b: 1 } }); | ||
getValue('a.b'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# propertyOf | ||
|
||
::: info | ||
この関数は互換性のために `es-toolkit/compat` からのみインポートできます。代替可能なネイティブ JavaScript API があるか、まだ十分に最適化されていないためです。 | ||
|
||
`es-toolkit/compat` からこの関数をインポートすると、[lodash と完全に同じように動作](../../../compatibility.md)します。 | ||
::: | ||
|
||
オブジェクトの指定されたパスで値を返す関数を作成します。 | ||
|
||
`property` は特定のパスにバインドされた関数を作成し、異なるオブジェクトをクエリすることができますが、 | ||
`propertyOf` は特定のオブジェクトにバインドされた関数を作成し、そのオブジェクト内の異なるパスをクエリすることができますます。 | ||
|
||
## インターフェース | ||
|
||
```typescript | ||
function propertyOf(object: unknown): (path: PropertyKey | PropertyKey[]) => unknown; | ||
``` | ||
|
||
### パラメータ | ||
|
||
- `object` (`unknown`): クエリするオブジェクトます。 | ||
|
||
### 戻り値 | ||
|
||
(`(path: PropertyKey | PropertyKey[]) => unknown`): パスを受け取り、指定されたパスのオブジェクトから値を取得する新しい関数を返します。 | ||
ます。 | ||
|
||
## 例 | ||
|
||
```typescript | ||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue('a.b.c'); | ||
console.log(result); // => 3 | ||
|
||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue(['a', 'b', 'c']); | ||
console.log(result); // => 3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# propertyOf | ||
|
||
::: info | ||
이 함수는 호환성을 위한 `es-toolkit/compat` 에서만 가져올 수 있어요. 대체할 수 있는 네이티브 JavaScript API가 있거나, 아직 충분히 최적화되지 않았기 때문이에요. | ||
|
||
`es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요. | ||
::: | ||
|
||
객체의 주어진 경로에 있는 값을 반환하는 함수를 생성해요. | ||
|
||
[`property`](./property.md)는 특정 경로에 바인딩된 함수를 생성하여 객체로부터 값을 검색할 수 있게 하고, | ||
`propertyOf`는 특정 객체에 바인딩된 함수를 생성하여 경로로부터 값을 검색할 수 있게 해요. | ||
|
||
## 인터페이스 | ||
|
||
```typescript | ||
function propertyOf(object: unknown): (path: PropertyKey | PropertyKey[]) => unknown; | ||
``` | ||
|
||
### 파라미터 | ||
|
||
- `object` (`unknown`): 검색할 객체. | ||
|
||
### 반환 값 | ||
|
||
(`(path: PropertyKey | PropertyKey[]) => unknown`): 경로를 입력받고 지정된 경로에서 객체의 값을 검색하는 함수. | ||
|
||
## 예시 | ||
|
||
```typescript | ||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue('a.b.c'); | ||
console.log(result); // => 3 | ||
|
||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue(['a', 'b', 'c']); | ||
console.log(result); // => 3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# propertyOf | ||
|
||
::: info | ||
This function is only available in `es-toolkit/compat` for compatibility reasons. It either has alternative native JavaScript APIs or isn’t fully optimized yet. | ||
|
||
When imported from `es-toolkit/compat`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md). | ||
::: | ||
|
||
Creates a function that returns the value at a given path of an object. | ||
|
||
Unlike [`property`](./property.md), which creates a function bound to a specific path and allows you to query different objects, | ||
`propertyOf` creates a function bound to a specific object and allows you to query different paths within that object. | ||
|
||
## Signature | ||
|
||
```typescript | ||
function propertyOf(object: unknown): (path: PropertyKey | PropertyKey[]) => unknown; | ||
``` | ||
|
||
### Parameters | ||
|
||
- `object` (`unknown`): The object to query. | ||
|
||
### Returns | ||
|
||
(`(path: PropertyKey | PropertyKey[]) => unknown`): Returns a new function that takes a path and retrieves the value from the object at the specified path. | ||
|
||
## Examples | ||
|
||
```typescript | ||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue('a.b.c'); | ||
console.log(result); // => 3 | ||
|
||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue(['a', 'b', 'c']); | ||
console.log(result); // => 3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# propertyOf | ||
|
||
::: info | ||
出于兼容性原因,此函数仅在 `es-toolkit/compat` 中提供。它可能具有替代的原生 JavaScript API,或者尚未完全优化。 | ||
|
||
从 `es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。 | ||
::: | ||
|
||
创建一个函数,该函数返回对象中特定路径的值。 | ||
|
||
与 `property` 不同,`property` 创建一个绑定到特定路径的函数,允许您查询不同的对象, | ||
`propertyOf` 创建一个绑定到特定对象的函数,允许您查询该对象内的不同路径。 | ||
|
||
## 签名 | ||
|
||
```typescript | ||
function propertyOf(object: unknown): (path: PropertyKey | PropertyKey[]) => unknown; | ||
``` | ||
|
||
### 参数 | ||
|
||
- `object` (`unknown`): 要查询的对象。 | ||
|
||
### 返回值 | ||
|
||
(`(path: PropertyKey | PropertyKey[]) => unknown`): 返回一个新函数,该函数接受一个路径并从指定路径的对象中检索值。 | ||
|
||
## 示例 | ||
|
||
```typescript | ||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue('a.b.c'); | ||
console.log(result); // => 3 | ||
|
||
const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
const result = getValue(['a', 'b', 'c']); | ||
console.log(result); // => 3 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { propertyOf } from './propertyOf'; | ||
import { noop } from '../../function'; | ||
import { constant } from '../util/constant'; | ||
import { times } from '../util/times'; | ||
|
||
describe('propertyOf', () => { | ||
it('should create a function that plucks a property value of a given key', () => { | ||
const object = { a: 1 }; | ||
const propOf = propertyOf(object); | ||
|
||
expect(propOf.length).toBe(1); | ||
['a', ['a']].forEach(path => { | ||
expect(propOf(path)).toBe(1); | ||
}); | ||
}); | ||
|
||
it('should pluck deep property values', () => { | ||
const object = { a: { b: 2 } }; | ||
const propOf = propertyOf(object); | ||
|
||
['a.b', ['a', 'b']].forEach(path => { | ||
expect(propOf(path)).toBe(2); | ||
}); | ||
}); | ||
|
||
it('should pluck inherited property values', () => { | ||
function Foo() { | ||
// @ts-expect-error type not defined | ||
this.a = 1; | ||
} | ||
Foo.prototype.b = 2; | ||
|
||
// @ts-expect-error type not defined | ||
const propOf = propertyOf(new Foo()); | ||
|
||
['b', ['b']].forEach(path => { | ||
expect(propOf(path)).toBe(2); | ||
}); | ||
}); | ||
|
||
it('should work with a non-string `path`', () => { | ||
const array = [1, 2, 3]; | ||
const propOf = propertyOf(array); | ||
|
||
[1, [1]].forEach(path => { | ||
expect(propOf(path)).toBe(2); | ||
}); | ||
}); | ||
|
||
it('should preserve the sign of `0`', () => { | ||
const object = { '-0': 'a', 0: 'b' }; | ||
const props = [-0, Object(-0), 0, Object(0)]; | ||
|
||
const actual = props.map(key => { | ||
const propOf = propertyOf(object); | ||
return propOf(key); | ||
}); | ||
|
||
expect(actual).toEqual(['a', 'a', 'b', 'b']); | ||
}); | ||
|
||
it('should coerce `path` to a string', () => { | ||
function fn() {} | ||
fn.toString = constant('fn'); | ||
|
||
const expected = [1, 2, 3, 4]; | ||
const object = { null: 1, undefined: 2, fn: 3, '[object Object]': 4 }; | ||
const paths = [null, undefined, fn, {}]; | ||
|
||
times(2, index => { | ||
const actual = paths.map(path => { | ||
const propOf = propertyOf(object); | ||
// @ts-expect-error invalid types | ||
return propOf(index ? [path] : path); | ||
}); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
}); | ||
|
||
it('should pluck a key over a path', () => { | ||
const object = { 'a.b': 1, a: { b: 2 } }; | ||
const propOf = propertyOf(object); | ||
|
||
['a.b', ['a.b']].forEach(path => { | ||
expect(propOf(path)).toBe(1); | ||
}); | ||
}); | ||
|
||
it('should return `undefined` when `object` is nullish', () => { | ||
// eslint-disable-next-line no-sparse-arrays | ||
const values = [, null, undefined]; | ||
const expected = values.map(noop); | ||
|
||
['constructor', ['constructor']].forEach(path => { | ||
const actual = values.map((value, index) => { | ||
// @ts-expect-error invalid types | ||
const propOf = index ? propertyOf(value) : propertyOf(); | ||
return propOf(path); | ||
}); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
}); | ||
|
||
it('should return `undefined` for deep paths when `object` is nullish', () => { | ||
// eslint-disable-next-line no-sparse-arrays | ||
const values = [, null, undefined]; | ||
const expected = values.map(noop); | ||
|
||
['constructor.prototype.valueOf', ['constructor', 'prototype', 'valueOf']].forEach(path => { | ||
const actual = values.map((value, index) => { | ||
// @ts-expect-error invalid types | ||
const propOf = index ? propertyOf(value) : propertyOf(); | ||
return propOf(path); | ||
}); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
}); | ||
|
||
it('should return `undefined` if parts of `path` are missing', () => { | ||
const propOf = propertyOf({}); | ||
|
||
['a', 'a[1].b.c', ['a'], ['a', '1', 'b', 'c']].forEach(path => { | ||
expect(propOf(path)).toBe(undefined); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { get } from './get.ts'; | ||
|
||
/** | ||
* Creates a function that returns the value at a given path of an object. | ||
* | ||
* Unlike `property`, which creates a function bound to a specific path and allows you to query different objects, | ||
* `propertyOf` creates a function bound to a specific object and allows you to query different paths within that object. | ||
* | ||
* @param {unknown} object - The object to query. | ||
* @returns {(path: PropertyKey | PropertyKey[]) => unknown} - Returns a new function that takes a path and retrieves the value from the object at the specified path. | ||
* | ||
* @example | ||
* const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
* const result = getValue('a.b.c'); | ||
* console.log(result); // => 3 | ||
* | ||
* @example | ||
* const getValue = propertyOf({ a: { b: { c: 3 } } }); | ||
* const result = getValue(['a', 'b', 'c']); | ||
* console.log(result); // => 3 | ||
*/ | ||
export function propertyOf(object: unknown): (path: PropertyKey | readonly PropertyKey[]) => unknown { | ||
return function (path: PropertyKey | readonly PropertyKey[]) { | ||
return get(object, path); | ||
}; | ||
} |