Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(findKey): add findKey to compat layer #828

Merged
merged 2 commits into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions benchmarks/performance/findKey.bench.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { bench, describe } from 'vitest';
import { findKey as findKeyToolkit } from 'es-toolkit';
import { findKey as findKeyCompatToolkit } from 'es-toolkit/compat';
import { findKey as findKeyLodash } from 'lodash';

describe('findKey', () => {
Expand All @@ -16,6 +17,10 @@ describe('findKey', () => {
bench('lodash/findKey', () => {
findKeyLodash(users, o => o.age < 40);
});

bench('es-toolkit/compat/findKey', () => {
findKeyCompatToolkit(users, o => o.age < 40);
});
});

describe('findKey/largeObject', () => {
Expand All @@ -31,4 +36,8 @@ describe('findKey/largeObject', () => {
bench('lodash/findKey', () => {
findKeyLodash(largeUsers, o => o.age === 7000);
});

bench('es-toolkit/compat/findKey', () => {
findKeyCompatToolkit(largeUsers, o => o.age === 7000);
});
});
50 changes: 46 additions & 4 deletions docs/ja/reference/object/findKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

提供されたテスト関数を満たすオブジェクト内の最初の要素のキーを検索します。

## Signature
## インターフェース

```typescript
function findKey<T extends Record<any, any>>(
Expand All @@ -11,16 +11,16 @@ function findKey<T extends Record<any, any>>(
): keyof T | undefined;
```

### Parameters
### パラメータ

- `obj` (`T extends Record<any, any>`): 検索するオブジェクト。
- `predicate` (`(value: T[keyof T], key: keyof T, obj: T) => boolean`): オブジェクト内の各値に対して実行する関数。

### Returns
### 戻り値

(`keyof T | undefined`): 指定されたテスト関数を満たすオブジェクト内の最初の要素のキー。テストに合格する要素がない場合は未定義です。

## Examples
##

```typescript
const users = {
Expand All @@ -32,3 +32,45 @@ const users = {
findKey(users, o => o.age < 40); // 'pebbles'
findKey(users, o => o.age > 50); // undefined
```

## Lodash 互換性

`es-toolkit/compat` から `findKey` をインポートすると、Lodash と互換になります。
キーを検索する条件を、さまざまな方法で指定できます。

- **検査関数**: 各要素に対して検査する関数を実行します。最初に `true` を返す要素のキーを返します。
- **部分オブジェクト**: 指定されたオブジェクトと部分的に一致する要素のキーを返します。
- **プロパティ-値ペア**: 指定されたプロパティと値が一致する要素のキーを返します。
- **プロパティ名**: 指定されたプロパティに対して真と評価される要素のキーを返します。

### インターフェース

```typescript
export function findKey<T extends Record<any, any>>(
obj: T,
conditionToFind: (value: T[keyof T], key: keyof T, obj: T) => boolean
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, objectToFind: Partial<T[keyof T]>): keyof T | undefined;
export function findKey<T extends Record<any, any>>(
obj: T,
propertyToFind: [keyof T[keyof T], any]
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, propertyToFind: keyof T[keyof T]): keyof T | undefined;
```

### 例

```typescript
const users = { barney: { age: 36 }, fred: { age: 40 } };

findKey(users, o => o.age < 40);
// => 'barney'
findKey(users, { age: 36 });
// => 'barney'
findKey(users, ['age', 36]);
// => 'barney'

const languages = { javascript: { active: false }, typescript: { active: true } };
findKey(users, 'active');
// => 'typescript'
```
43 changes: 43 additions & 0 deletions docs/ko/reference/object/findKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,46 @@ const users = {
findKey(users, o => o.age < 40); // 'pebbles'
findKey(users, o => o.age > 50); // undefined
```

## Lodash와 호환성

`es-toolkit/compat`에서 `findKey`를 가져오면 lodash와 완전히 호환돼요.

키를 찾는 조건을 여러 방법으로 명시할 수 있어요.

- **검사 함수**: 각각의 요소에 대해서 검사하는 함수를 실행해요. 처음으로 `true`를 반환하는 요소의 키를 반환해요.
- **부분 객체**: 주어진 객체와 부분적으로 일치하는 요소의 키를 반환해요.
- **프로퍼티-값 쌍**: 해당 프로퍼티와 값이 일치하는 요소의 키를 반환해요.
- **프로퍼티 이름**: 해당 프로퍼티에 대해서 참으로 평가되는 요소의 키를 반환해요.

### 인터페이스

```typescript
export function findKey<T extends Record<any, any>>(
obj: T,
conditionToFind: (value: T[keyof T], key: keyof T, obj: T) => boolean
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, objectToFind: Partial<T[keyof T]>): keyof T | undefined;
export function findKey<T extends Record<any, any>>(
obj: T,
propertyToFind: [keyof T[keyof T], any]
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, propertyToFind: keyof T[keyof T]): keyof T | undefined;
```

### 예시

```typescript
const users = { barney: { age: 36 }, fred: { age: 40 } };

findKey(users, o => o.age < 40);
// => 'barney'
findKey(users, { age: 36 });
// => 'barney'
findKey(users, ['age', 36]);
// => 'barney'

const languages = { javascript: { active: false }, typescript: { active: true } };
findKey(users, 'active');
// => 'typescript'
```
43 changes: 43 additions & 0 deletions docs/reference/object/findKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,46 @@ const users = {
findKey(users, o => o.age < 40); // 'pebbles'
findKey(users, o => o.age > 50); // undefined
```

## Compatibility with Lodash

Import `findKey` from `es-toolkit/compat` for full compatibility with lodash.

You can specify the condition for finding keys in several ways:

- **Predicate function**: You can provide a predicate function that will be applied to each value in the object. The function should return `true` for elements that match the criteria. The search continues until the predicate returns `true` for the first time.
- **Partial object**: You can also provide a partial object, and the function will return the key of the first element in the object that matches the properties of the provided object.
- **Property-value pair**: Alternatively, you can specify a property-value pair, where the function will return the key of the first element that has the specified property matching the given value.
- **Property name**: Lastly, you can provide a property name, and the function will return the key of the first element where the specified property has a truthy value.

### Signature

```typescript
export function findKey<T extends Record<any, any>>(
obj: T,
conditionToFind: (value: T[keyof T], key: keyof T, obj: T) => boolean
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, objectToFind: Partial<T[keyof T]>): keyof T | undefined;
export function findKey<T extends Record<any, any>>(
obj: T,
propertyToFind: [keyof T[keyof T], any]
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, propertyToFind: keyof T[keyof T]): keyof T | undefined;
```

### Examples

```typescript
const users = { barney: { age: 36 }, fred: { age: 40 } };

findKey(users, o => o.age < 40);
// => 'barney'
findKey(users, { age: 36 });
// => 'barney'
findKey(users, ['age', 36]);
// => 'barney'

const languages = { javascript: { active: false }, typescript: { active: true } };
findKey(users, 'active');
// => 'typescript'
```
43 changes: 43 additions & 0 deletions docs/zh_hans/reference/object/findKey.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,46 @@ const users = {
findKey(users, o => o.age < 40); // 'pebbles'
findKey(users, o => o.age > 50); // undefined
```

## Lodash 兼容性

从 `es-toolkit/compat` 导入 `findKey` 以实现与 lodash 的完全兼容。

您可以通过多种方式指定查找键的条件。

- **谓词函数**:对每个元素执行谓词函数。返回第一个返回 `true` 的元素的键。
- **部分对象**:返回与给定对象部分匹配的元素的键。
- **属性-值对**:返回具有指定属性和值匹配的元素的键。
- **属性名**:返回指定属性评估为真的元素的键。

### 签名

```typescript
export function findKey<T extends Record<any, any>>(
obj: T,
conditionToFind: (value: T[keyof T], key: keyof T, obj: T) => boolean
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, objectToFind: Partial<T[keyof T]>): keyof T | undefined;
export function findKey<T extends Record<any, any>>(
obj: T,
propertyToFind: [keyof T[keyof T], any]
): keyof T | undefined;
export function findKey<T extends Record<any, any>>(obj: T, propertyToFind: keyof T[keyof T]): keyof T | undefined;
```

### 示例

```typescript
const users = { barney: { age: 36 }, fred: { age: 40 } };

findKey(users, o => o.age < 40);
// => 'barney'
findKey(users, { age: 36 });
// => 'barney'
findKey(users, ['age', 36]);
// => 'barney'

const languages = { javascript: { active: false }, typescript: { active: true } };
findKey(users, 'active');
// => 'typescript'
```
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export { sumBy } from './math/sumBy.ts';

export { cloneDeep } from './object/cloneDeep.ts';
export { defaults } from './object/defaults.ts';
export { findKey } from './object/findKey.ts';
export { fromPairs } from './object/fromPairs.ts';
export { get } from './object/get.ts';
export { has } from './object/has.ts';
Expand Down
61 changes: 61 additions & 0 deletions src/compat/object/findKey.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { describe, expect, it } from 'vitest';
import { findKey } from './findKey';

/**
* @see https://lodash.com/docs/4.17.15#findKey
*/
describe('findKey', () => {
const users = {
barney: { age: 36, active: true },
fred: { age: 40, active: false },
pebbles: { age: 1, active: true },
};

it('should find key with a function predicate', function () {
const actual = findKey(users, function (o) {
return o.age < 40;
});
expect(actual).toBe('barney');
});

it('should work with `_.matches` shorthands', function () {
const actual = findKey(users, { age: 1, active: true });
expect(actual).toBe('pebbles');
});

it('should work with `_.matchesProperty` shorthands', function () {
const actual = findKey(users, ['active', false]);
expect(actual).toBe('fred');
});

it('should work with `_.property` shorthands', function () {
const actual = findKey(users, 'active');
expect(actual).toBe('barney');
});

it('should return undefined for an empty object', function () {
// @ts-expect-error - invalid argument
const actual = findKey({}, { age: 36 });
expect(actual).toBeUndefined();
});

it('should return undefined for null input', function () {
const actual = findKey(null, { age: 36 });
expect(actual).toBeUndefined();
});

it('should return undefined for undefined input', function () {
const actual = findKey(undefined, { age: 36 });
expect(actual).toBeUndefined();
});

it('should return undefined if no matching key is found', function () {
const actual = findKey(users, { age: 100 });
expect(actual).toBeUndefined();
});

it('should handle partial matches with `Partial<T[keyof T]>`', function () {
const actual = findKey(users, { active: true });
expect(actual).toBe('barney');
});
});
Loading