From 1497a949f9de7c14d8683f160551c3715525119e Mon Sep 17 00:00:00 2001 From: D-Sketon <2055272094@qq.com> Date: Sat, 19 Oct 2024 20:56:49 +0800 Subject: [PATCH] fix(some): fix lodash compatibility (#728) --- docs/ja/reference/compat/array/some.md | 100 ++++++++++-- docs/ko/reference/compat/array/some.md | 117 ++++++++++++-- docs/reference/compat/array/some.md | 115 +++++++++++-- docs/zh_hans/reference/compat/array/some.md | 116 ++++++++++++-- src/compat/array/some.spec.ts | 61 +++++++ src/compat/array/some.ts | 169 +++++++++++++++----- 6 files changed, 575 insertions(+), 103 deletions(-) diff --git a/docs/ja/reference/compat/array/some.md b/docs/ja/reference/compat/array/some.md index 004d028f..99f57f8e 100644 --- a/docs/ja/reference/compat/array/some.md +++ b/docs/ja/reference/compat/array/some.md @@ -6,7 +6,7 @@ `es-toolkit/compat` からこの関数をインポートすると、[lodash と完全に同じように動作](../../../compatibility.md)します。 ::: -配列内に指定された条件と一致する要素があるかどうかを確認します。 +配列またはオブジェクト内の要素が指定された条件を満たすかどうかを確認します。 条件は複数の方法で指定できます。 @@ -15,25 +15,46 @@ - **プロパティ-値ペア**: 該当プロパティに対して値が一致する最初の要素が選択されます。 - **プロパティ名**: 該当プロパティに対して真と評価される値を持つ最初の要素が選択されます。 -条件が提供されていない場合、関数は配列内に真と評価される要素があるかどうかを確認します。 +条件が指定されていない場合、配列またはオブジェクトに真と評価される要素があるか確認します。 ## インターフェース ```typescript +function some(arr: T[]): boolean; function some(arr: T[], predicate: (item: T, index: number, arr: any) => unknown): boolean; function some(arr: T[], predicate: [keyof T, unknown]): boolean; function some(arr: T[], predicate: string): boolean; function some(arr: T[], predicate: Partial): boolean; + +function some>(object: T): boolean; +function some>( + object: T, + predicate: (value: T[keyof T], key: keyof T, object: T) => unknown +): boolean; +function some>(object: T, predicate: Partial): boolean; +function some>(object: T, predicate: [keyof T[keyof T], unknown]): boolean; +function some>(object: T, predicate: string): boolean; ``` ### パラメータ -- `arr` (`T[]`): 反復する配列です。 -- `predicate` (`((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string`): - - **検査関数** (`(item: T, index: number, arr: T[]) => unknown`): 探している要素かどうかを返す関数。 - - **部分オブジェクト** (`Partial`): 一致させるプロパティと値を指定した部分オブジェクト。 - - **プロパティ-値ペア** (`[keyof T, unknown]`): 最初が一致させるプロパティ、2番目が一致させる値を表すタプル。 - - **プロパティ名** (`string`): 真と評価される値を持っているか確認するプロパティ名。 +- `arr` (`T[]`) または `object` (`T`): 反復する配列です。 + +- `predicate`: + + - 配列の場合: + + - **検査関数** (`(item: T, index: number, arr: T[]) => unknown`): 各要素に対して検査する関数。 + - **部分オブジェクト** (`Partial`): 部分的に一致するプロパティを持つ最初の要素を返す。 + - **プロパティ-値ペア** (`[keyof T, unknown]`): 最初が一致させるプロパティ、2番目が一致させる値を表すタプル。 + - **プロパティ名** (`string`): 真と評価される値を持っているか確認するプロパティ名。 + + - オブジェクトの場合: + + - **検査関数** (`(value: T[keyof T], key: keyof T, object: T) => unknown`): 条件を満たすかどうかを確認する関数。 + - **部分オブジェクト** (`Partial`): 部分的に一致するプロパティを持つ最初の要素を返す。 + - **プロパティ-値ペア** (`[keyof T[keyof T], unknown]`): 最初が一致させるプロパティ、2番目が一致させる値を表すタプル。 + - **プロパティ名** (`string`): 真と評価される値を持っているか確認するプロパティ名。 ### 戻り値 @@ -41,16 +62,63 @@ function some(arr: T[], predicate: Partial): boolean; ## 例 +### 配列の場合 + ```typescript -some([1, 2, 3, 4], n => n % 2 === 0); -// => true +import { some } from 'es-toolkit/compat'; -some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); -// => true +// 検査関数を使う場合 +let items = [1, 2, 3, 4, 5]; +let result = some(items, item => item > 3); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); -// => true +// 部分オブジェクトを使う場合 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, { name: 'Bob' }); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); -// => true +// プロパティ-値ペアを使う場合 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, ['name', 'Bob']); +console.log(result); // true + +// プロパティ名を使う場合 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, 'name'); +console.log(result); // true +``` + +### オブジェクトの場合 + +```typescript +import { some } from 'es-toolkit/compat'; + +// 検査関数を使う場合 +let obj = { a: 1, b: 2, c: 3 }; +let result = some(object, value => value > 2); +console.log(result); // true + +// 部分オブジェクトを使う場合 +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, { name: 'Bob' }); +console.log(result); // true + +// プロパティ-値ペアを使う場合 +obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; +result = some(obj, ['name', 'Bob']); +console.log(result); // true + +// プロパティ名を使う場合 +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, 'name'); +console.log(result); // true ``` diff --git a/docs/ko/reference/compat/array/some.md b/docs/ko/reference/compat/array/some.md index e2ff702b..c0f2116a 100644 --- a/docs/ko/reference/compat/array/some.md +++ b/docs/ko/reference/compat/array/some.md @@ -6,7 +6,7 @@ `es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요. ::: -주어진 조건을 만족하는 요소가 배열에 있는지 확인해요. +배열이나 객체의 요소 중 주어진 조건을 만족하는 요소가 있는지 확인해요. 조건은 여러 방법들로 명시할 수 있어요. @@ -15,25 +15,63 @@ - **프로퍼티-값 쌍**: 해당 프로퍼티에 대해서 값이 일치하는 첫 번째 요소가 선택돼요. - **프로퍼티 이름**: 해당 프로퍼티에 대해서 참으로 평가되는 값을 가지는 첫 번째 요소가 선택돼요. -조건이 주어지지 않았다면, 배열에 참으로 평가받는 요소가 있는지 확인해요. +조건이 제공되지 않으면, 배열이나 객체에 참으로 평가되는 요소가 있는지 확인해요. ## 인터페이스 ```typescript +function some(arr: T[]): boolean; function some(arr: T[], predicate: (item: T, index: number, arr: any) => unknown): boolean; function some(arr: T[], predicate: [keyof T, unknown]): boolean; function some(arr: T[], predicate: string): boolean; function some(arr: T[], predicate: Partial): boolean; + +function some>(object: T): boolean; +function some>( + object: T, + predicate: (value: T[keyof T], key: keyof T, object: T) => unknown +): boolean; +function some>(object: T, predicate: Partial): boolean; +function some>(object: T, predicate: [keyof T[keyof T], unknown]): boolean; +function some>(object: T, predicate: string): boolean; ``` ### 파라미터 -- `arr` (`T[]`): 반복할 배열. -- `predicate` (`((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string`): - - **검사 함수** (`(item: T, index: number, arr: T[]) => unknown`): 찾는 요소인지 여부를 반환하는 함수. - - **부분 객체** (`Partial`): 일치시킬 프로퍼티와 값들을 명시한 부분 객체. - - **프로퍼티-값 쌍** (`[keyof T, unknown]`): 첫 번째가 일치시킬 프로퍼티, 두 번째가 일치시킬 값을 나타내는 튜플. - - **프로퍼티 이름** (`string`): 참으로 평가되는 값을 가지고 있는지 확인할 프로퍼티 이름. +- `arr` (`T[]`) 또는 `object` (`T`): 반복할 배열. + +::: info `arr`는 `ArrayLike`일 수도 있고, `null` 또는 `undefined`일 수도 있어요 + +lodash와 완벽하게 호환되도록 `every` 함수는 `arr`을 다음과 같이 처리해요: + +- `arr`가 `ArrayLike`인 경우 `Array.from(...)`을 사용하여 배열로 변환해요. +- `arr`가 `null` 또는 `undefined`인 경우 빈 배열로 간주돼요. + +::: + +::: info `object`는 `null` 또는 `undefined`일 수도 있어요 + +lodash와 완벽하게 호환되도록 `every` 함수는 `object`를 다음과 같이 처리해요: + +- `object`가 `null` 또는 `undefined`인 경우 빈 객체로 변환돼요. + +::: + +- `predicate`: + + - 배열의 경우: + + - **검사 함수** (`(item: T, index: number, arr: any) => unknown`): 요소, 인덱스, 배열을 받아 조건을 만족하면 `true`를 반환하는 함수. + - **부분 객체** (`Partial`): 일치시킬 프로퍼티와 값들을 명시한 부분 객체. + - **프로퍼티-값 쌍** (`[keyof T, unknown]`): 첫 번째가 일치시킬 프로퍼티, 두 번째가 일치시킬 값을 나타내는 튜플. + - **프로퍼티 이름** (`string`): 참으로 평가되는 값을 가지고 있는지 확인할 프로퍼티 이름. + + - 객체의 경우: + + - **검사 함수** (`(value: T[keyof T], key: keyof T, object: T) => unknown`): 값, 키, 객체를 받아 조건을 만족하면 `true`를 반환하는 함수. + - **부분 값** (`Partial`): 값과 일치시킬 부분 값을 명시한 부분 객체. + - **프로퍼티-값 쌍** (`[keyof T[keyof T], unknown]`): 첫 번째가 일치시킬 프로퍼티, 두 번째가 일치시킬 값을 나타내는 튜플. + - **프로퍼티 이름** (`string`): 참으로 평가되는 값을 가지고 있는지 확인할 프로퍼티 이름. ### 반환 값 @@ -41,16 +79,63 @@ function some(arr: T[], predicate: Partial): boolean; ## 예시 +### 배열의 경우 + ```typescript -some([1, 2, 3, 4], n => n % 2 === 0); -// => true +import { every } from 'es-toolkit/compat'; -some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); -// => true +// 검사 함수를 쓰는 경우 +const items = [1, 2, 3, 4, 5]; +const result = every(items, item => item > 0); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); -// => true +// 부분 객체를 쓰는 경우 +const items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +const result = every(items, { name: 'Bob' }); +console.log(result); // false -some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); -// => true +// 프로퍼티-값 쌍을 쓰는 경우 +const items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +const result = every(items, ['name', 'Alice']); +console.log(result); // false + +// 프로퍼티 이름을 쓰는 경우 +const items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +const result = every(items, 'name'); +console.log(result); // true +``` + +### 객체의 경우 + +```typescript +import { every } from 'es-toolkit/compat'; + +// 검사 함수를 쓰는 경우 +const obj = { a: 1, b: 2, c: 3 }; +const result = every(obj, value => value > 0); +console.log(result); // true + +// 부분 객체를 쓰는 경우 +const obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +const result = every(obj, { name: 'Bob' }); +console.log(result); // false + +// 프로퍼티-값 쌍을 쓰는 경우 +const obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; +const result = every(obj, ['name', 'Alice']); +console.log(result); // false + +// 프로퍼티 이름을 쓰는 경우 +const obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +const result = every(obj, 'name'); +console.log(result); // true ``` diff --git a/docs/reference/compat/array/some.md b/docs/reference/compat/array/some.md index 335c8935..2af8aa17 100644 --- a/docs/reference/compat/array/some.md +++ b/docs/reference/compat/array/some.md @@ -6,7 +6,7 @@ This function is only available in `es-toolkit/compat` for compatibility reasons When imported from `es-toolkit/compat`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md). ::: -Checks if there is an element in an array that matches the given predicate. +Checks if there is an element in an array or object that matches the given predicate. You can specify the condition in several ways: @@ -15,7 +15,7 @@ You can specify the condition in several ways: - **Property-value pair**: If you provide a property-value pair, the function will return the first item that matches the property and value from the pair. - **Property name**: If you provide a property name, the function will return the first item where the specified property has a truthy value. -If no predicate is provided, the function checks if there is any truthy element in the array. +If no predicate is provided, the function checks if there is any truthy element in the array or object. ## Signature @@ -25,16 +25,52 @@ function some(arr: T[], predicate: (item: T, index: number, arr: any) => unkn function some(arr: T[], predicate: [keyof T, unknown]): boolean; function some(arr: T[], predicate: string): boolean; function some(arr: T[], predicate: Partial): boolean; + +function some>(object: T): boolean; +function some>( + object: T, + predicate: (value: T[keyof T], key: keyof T, object: T) => unknown +): boolean; +function some>(object: T, predicate: Partial): boolean; +function some>(object: T, predicate: [keyof T[keyof T], unknown]): boolean; +function some>(object: T, predicate: string): boolean; ``` ### Parameters -- `arr` (`T[]`): The array to iterate over. -- `predicate` (`((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string`): - - **Predicate function** (`(item: T, index: number, arr: T[]) => unknown`): A function that takes an item, its index, and the array, and returns a truthy value if the item matches the criteria. - - **Partial object** (`Partial`): A partial object that specifies the properties to match. - - **Property-value pair** (`[keyof T, unknown]`): An array where the first element is the property key and the second element is the value to match. - - **Property name** (`string`): The name of the property to check for a truthy value. +- `arr` (`T[]`) or `object` (`T`): The array or object to iterate over. + +::: info `arr` can be `ArrayLike`, `null`, or `undefined` + +To ensure full compatibility with lodash, the `some` function handles `arr` in this way: + +- If `arr` is an `ArrayLike`, it gets converted into an array using `Array.from(...)`. +- If `arr` is `null` or `undefined`, it will be treated as an empty array. + +::: + +::: info `object` can be `null` or `undefined` + +To ensure full compatibility with lodash, the `some` function handles `object` in this way: + +- If `object` is `null` or `undefined`, it will be converted into an empty object. + +::: + +- `predicate`: + + - For the `some` overload with arrays: + + - **Predicate function** (`(item: T, index: number, arr: T[]) => unknown`): A function that takes an item, its index, and the array, and returns a truthy value if the item matches the criteria. + - **Partial object** (`Partial`): A partial object that specifies the properties to match. + - **Property-value pair** (`[keyof T, unknown]`): An array where the first element is the property key and the second element is the value to match. + - **Property name** (`string`): The name of the property to check for a truthy value. + + - For the `some` overloads with objects: + - **Predicate function** (`(value: T[keyof T], key: keyof T, object: T) => unknown`): A function that takes an value, its key, and the object, and returns a truthy value if the item matches the criteria. + - **Partial value** (`Partial`): A partial value to match against the values of the object. + - **Property-value pair** (`[keyof T[keyof T], unknown]`): An array where the first element is the property key and the second element is the value to match. + - **Property name** (`string`): The name of the property to check for a truthy value. ### Returns @@ -42,16 +78,63 @@ function some(arr: T[], predicate: Partial): boolean; ## Examples +### Arrays + ```typescript -some([1, 2, 3, 4], n => n % 2 === 0); -// => true +import { some } from 'es-toolkit/compat'; -some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); -// => true +// Using a predicate function +let items = [1, 2, 3, 4, 5]; +let result = some(items, item => item > 3); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); -// => true +// Using a partial object +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, { name: 'Bob' }); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); -// => true +// Using a property-value pair +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, ['name', 'Bob']); +console.log(result); // true + +// Using a property name +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, 'name'); +console.log(result); // true +``` + +### Objects + +```typescript +import { some } from 'es-toolkit/compat'; + +// Using a predicate function +let obj = { a: 1, b: 2, c: 3 }; +let result = some(object, value => value > 2); +console.log(result); // true + +// Using a partial value +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, { name: 'Bob' }); +console.log(result); // true + +// Using a property-value pair +obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; +result = some(obj, ['name', 'Bob']); +console.log(result); // true + +// Using a property name +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, 'name'); +console.log(result); // true ``` diff --git a/docs/zh_hans/reference/compat/array/some.md b/docs/zh_hans/reference/compat/array/some.md index 2c9aa077..e6aecbe5 100644 --- a/docs/zh_hans/reference/compat/array/some.md +++ b/docs/zh_hans/reference/compat/array/some.md @@ -6,7 +6,7 @@ 从 `es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。 ::: -检查数组中是否有元素满足给定的条件。 +检查数组或对象中是否有元素满足给定的条件。 您可以通过以下几种方式指定条件: @@ -15,7 +15,7 @@ - **属性-值对**:如果提供一个属性-值对,该函数将返回第一个匹配该属性和值的项。 - **属性名称**:如果提供一个属性名称,该函数将返回第一个指定属性具有真值的项。 -如果没有提供条件,该函数会检查数组中是否有任何值为真的元素。 +如果没有提供条件,该函数会检查数组或对象中是否有任何值为真的元素。 ## 签名 @@ -25,16 +25,53 @@ function some(arr: T[], predicate: (item: T, index: number, arr: any) => unkn function some(arr: T[], predicate: [keyof T, unknown]): boolean; function some(arr: T[], predicate: string): boolean; function some(arr: T[], predicate: Partial): boolean; + +function some>(object: T): boolean; +function some>( + object: T, + predicate: (value: T[keyof T], key: keyof T, object: T) => unknown +): boolean; +function some>(object: T, predicate: Partial): boolean; +function some>(object: T, predicate: [keyof T[keyof T], unknown]): boolean; +function some>(object: T, predicate: string): boolean; ``` ### 参数 -- `arr` (`T[]`): 要迭代的数组。 -- `predicate` (`((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string`): - - **谓词函数** (`(item: T, index: number, arr: T[]) => unknown`): 一个函数,接受项、其索引和数组,如果项符合条件则返回真值。 - - **部分对象** (`Partial`): 指定要匹配的属性的部分对象。 - - **属性-值对** (`[keyof T, unknown]`): 一个数组,第一个元素是属性键,第二个元素是要匹配的值。 - - **属性名称** (`string`): 要检查其真值的属性名称。 +- `arr` (`T[]`) 或 `object` (`T`): 要迭代的数组或对象。 + +::: info `arr` 可以是 `ArrayLike`、`null` 或 `undefined` + +为了确保与 lodash 的完全兼容性,`every` 函数会按照以下方式处理 `arr`: + +- 如果 `arr` 是 `ArrayLike`,它将使用 `Array.from(...)` 转换为数组。 +- 如果 `arr` 是 `null` 或 `undefined`,它将被视为一个空数组。 + +::: + +::: info `object` 可以是 `null` 或 `undefined` + +为了确保与 lodash 的完全兼容性,`every` 函数会按照以下方式处理 `object`: + +- 如果 `object` 是 `null` 或 `undefined`,它将被转换为一个空对象。 + +::: + +- `predicate`: + + - 对于数组的 `some` 重载: + + - **谓词函数** (`(item: T, index: number, arr: T[]) => unknown`): 一个函数,接受项、其索引和数组,如果项符合条件则返回真值。 + - **部分对象** (`Partial`): 指定要匹配的属性的部分对象。 + - **属性-值对** (`[keyof T, unknown]`): 一个数组,第一个元素是属性键,第二个元素是要匹配的值。 + - **属性名称** (`string`): 要检查其真值的属性名称。 + + - 对于对象的`some`重载: + + - **谓词函数** (`(value: T[keyof T], key: keyof T, object: T) => unknown`): 一个函数,接受值、其键和对象,如果值符合条件则返回真值。 + - **部分值** (`Partial`): 要与对象的值匹配的部分值。 + - **属性-值对** (`[keyof T[keyof T], unknown]`): 一个数组,第一个元素是属性键,第二个元素是要匹配的值。 + - **属性名称** (`string`): 要检查其真值的属性名称。 ### 返回值 @@ -42,16 +79,63 @@ function some(arr: T[], predicate: Partial): boolean; ## 示例 +### 数组 + ```typescript -some([1, 2, 3, 4], n => n % 2 === 0); -// => true +import { some } from 'es-toolkit/compat'; -some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); -// => true +// 使用谓词函数 +let items = [1, 2, 3, 4, 5]; +let result = some(items, item => item > 3); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); -// => true +// 使用部分对象 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, { name: 'Bob' }); +console.log(result); // true -some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); -// => true +// 使用属性-值对 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, ['name', 'Bob']); +console.log(result); // true + +// 使用属性名称 +items = [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, +]; +result = some(items, 'name'); +console.log(result); // true +``` + +### 对象 + +```typescript +import { some } from 'es-toolkit/compat'; + +// 使用谓词函数 +let obj = { a: 1, b: 2, c: 3 }; +let result = some(object, value => value > 2); +console.log(result); // true + +// 使用部分对象 +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, { name: 'Bob' }); +console.log(result); // true + +// 使用属性-值对 +obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; +result = some(obj, ['name', 'Bob']); +console.log(result); // true + +// 使用属性名称 +obj = { a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }; +result = some(obj, 'name'); +console.log(result); // true ``` diff --git a/src/compat/array/some.spec.ts b/src/compat/array/some.spec.ts index ab077edb..361c9beb 100644 --- a/src/compat/array/some.spec.ts +++ b/src/compat/array/some.spec.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from 'vitest'; import { some } from './some'; +import { args } from '../_internal/args'; import { empties } from '../_internal/empties'; import { identity } from '../_internal/identity'; import { stubFalse } from '../_internal/stubFalse'; @@ -72,6 +73,30 @@ describe('some', () => { }); expect(actual).toEqual(expected); + + expected = values.map(stubFalse); + actual = values.map((value, index) => { + const array = { 0: 0, a: 0 }; + return index + ? // eslint-disable-next-line + // @ts-ignore + some(array, value) + : some(array); + }); + + expect(actual).toEqual(expected); + + expected = values.map(stubTrue); + actual = values.map((value, index) => { + const array = { 0: 0, a: 1 }; + return index + ? // eslint-disable-next-line + // @ts-ignore + some(array, value) + : some(array); + }); + + expect(actual).toEqual(expected); }); it('should work with `_.property` shorthands', () => { @@ -105,4 +130,40 @@ describe('some', () => { const actual = [[1]].map(some); expect(actual).toEqual([true]); }); + + it('should return true for object with one value passing the predicate', () => { + expect(some({ a: 1, b: 2, c: 3 }, value => value >= 3)).toBe(true); + }); + + it('should return false for object with all values failing the predicate', () => { + expect(some({ a: 1, b: 2, c: 3 }, value => value > 3)).toBe(false); + }); + + it('should return true for object with one value matching the partial', () => { + expect(some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, { name: 'Bob' })).toBe(true); + }); + + it('should return true for object with one value matching the property', () => { + expect(some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, 'name')).toBe(true); + }); + + it('should return true for object with one value matching the property and value', () => { + expect(some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, ['name', 'Bob'])).toBe(true); + }); + + it('should return false for empty object', () => { + const result = some({}, () => false); + expect(result).toBe(false); + }); + + it('should return false when provided `null` or `undefined`', () => { + expect(some(null, identity)).toBe(false); + expect(some(undefined, identity)).toBe(false); + }); + + it('should support array-like objects', () => { + expect(some({ 0: 'a', 1: 'b', length: 2 }, value => value === 'b')).toBe(true); + expect(some('123', value => value === '3')).toBe(true); + expect(some(args, value => value === 1)).toBe(true); + }); }); diff --git a/src/compat/array/some.ts b/src/compat/array/some.ts index d50b3ca8..b3451da6 100644 --- a/src/compat/array/some.ts +++ b/src/compat/array/some.ts @@ -6,32 +6,38 @@ import { matchesProperty } from '../predicate/matchesProperty.ts'; /** * Checks if there is an element in an array that is truthy. * - * @param {T[]} arr The array to iterate over. + * @template T + * @param {ArrayLike | null | undefined} arr The array to iterate over. * @returns {boolean} Returns `true` if any element is truthy, else `false`. * * @example * some([1, 2, 3, 4]); * // => true */ -export function some(arr: readonly T[]): boolean; +export function some(arr: ArrayLike | null | undefined): boolean; /** * Checks if there is an element in an array that matches the given predicate function. * - * @param {T[]} arr The array to iterate over. - * @param {(item: T, index: number, arr: any) => unknown} predicate The function invoked per iteration. + * @template T + * @param {ArrayLike | null | undefined} arr The array to iterate over. + * @param {(item: T, index: number, arr: readonly T[]) => unknown} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. * * @example * some([1, 2, 3, 4], n => n % 2 === 0); * // => true */ -export function some(arr: readonly T[], predicate: (item: T, index: number, arr: any) => unknown): boolean; +export function some( + arr: ArrayLike | null | undefined, + predicate: (item: T, index: number, arr: readonly T[]) => unknown +): boolean; /** * Checks if there is an element in an array that matches the given key-value pair. * - * @param {T[]} arr The array to iterate over. + * @template T + * @param {ArrayLike | null | undefined} arr The array to iterate over. * @param {[keyof T, unknown]} predicate The key-value pair to match. * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. * @@ -39,12 +45,13 @@ export function some(arr: readonly T[], predicate: (item: T, index: number, a * some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); * // => true */ -export function some(arr: readonly T[], predicate: [keyof T, unknown]): boolean; +export function some(arr: ArrayLike | null | undefined, predicate: [keyof T, unknown]): boolean; /** * Checks if there is an element in an array that has a truthy value for the given property name. * - * @param {T[]} arr The array to iterate over. + * @template T + * @param {ArrayLike | null | undefined} arr The array to iterate over. * @param {string} propertyToCheck The property name to check. * @returns {boolean} Returns `true` if any element has a truthy value for the property, else `false`. * @@ -52,12 +59,13 @@ export function some(arr: readonly T[], predicate: [keyof T, unknown]): boole * some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); * // => true */ -export function some(arr: readonly T[], propertyToCheck: string): boolean; +export function some(arr: ArrayLike | null | undefined, propertyToCheck: string): boolean; /** * Checks if there is an element in an array that matches the given partial object. * - * @param {T[]} arr The array to iterate over. + * @template T + * @param {ArrayLike | null | undefined} arr The array to iterate over. * @param {Partial} doesMatch The partial object to match. * @returns {boolean} Returns `true` if any element matches the partial object, else `false`. * @@ -65,43 +73,99 @@ export function some(arr: readonly T[], propertyToCheck: string): boolean; * some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); * // => true */ -export function some(arr: readonly T[], doesMatch: Partial): boolean; +export function some(arr: ArrayLike | null | undefined, doesMatch: Partial): boolean; /** - * Checks if there is an element in an array that matches the given predicate. * - * Iteration is stopped once there is an element that matches `predicate`. + * Checks if there is an element in an object that matches the given predicate function. * - * @param {T[]} arr The array to iterate over. - * @param {((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string} [predicate=identity] The function invoked per iteration. - * If a property name or an object is provided it will be used to create a predicate function. + * @template T + * @param {T | null | undefined} object The object to iterate over. + * @returns {boolean} Returns `true` if any element is truthy, else `false`. + * + * @example + * some({ a: 1, b: 2, c: 3 }); + * // => true + */ +export function some>(object: T | null | undefined): boolean; + +/** + * + * Checks if there is an element in an object that matches the given predicate function. + * + * @template T + * @param {T | null | undefined} object The object to iterate over. + * @param {(value: T[keyof T], key: keyof T, object: T) => unknown} doesMatch A function that takes an value, its key, and the object, and returns a truthy value if the item matches the criteria. * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. * * @example - * some([1, 2, 3, 4], n => n % 2 === 0); - * // => true - * - * some([{ a: 1 }, { a: 2 }, { a: 3 }], { a: 2 }); - * // => true - * - * some([{ a: 1 }, { a: 2 }, { a: 3 }], ['a', 2]); - * // => true - * - * some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); + * some({ a: 1, b: 2, c: 3 }, n => n % 2 === 0); * // => true */ -export function some( - arr: readonly T[] | null | undefined, - predicate?: ((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string, - guard?: unknown +export function some>( + object: T | null | undefined, + doesMatch: (value: T[keyof T], key: keyof T, object: T) => unknown ): boolean; +/** + * + * Checks if there is an element in an object that matches the given partial value. + * + * @template T + * @param {T | null | undefined} object The object to iterate over. + * @param {Partial} doesMatch A partial value to match against the values of the object. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. + * + * @example + * some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, { name: 'Bob' }); + * // => true + */ +export function some>( + object: T | null | undefined, + doesMatch: Partial +): boolean; + +/** + * + * Checks if there is an element in an object that matches a property with a specific value. + * + * @template T + * @param {T | null | undefined} object The object to iterate over. + * @param {[keyof T, unknown]} doesMatchProperty An array where the first element is the property key and the second element is the value to match. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. + * + * @example + * const obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; + * const result = some(obj, ['name', 'Alice']); + * // => true + */ +export function some>( + object: T | null | undefined, + doesMatchProperty: [keyof T[keyof T], unknown] +): boolean; + +/** + * + * Checks if there is an element in an object that has a specific property, where the property name is provided as a string. + * + * @template T + * @param {T | null | undefined} object The object to iterate over. + * @param {string} propertyToCheck The property name to check. + * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. + * + * @example + * const obj = { alice: { id: 1, name: 'Alice' }, bob: { id: 2, name: 'Bob' } }; + * const result = some(obj, 'name'); + * // => true + */ +export function some>(object: T | null | undefined, propertyToCheck: string): boolean; /** * Checks if there is an element in an array that matches the given predicate. * * Iteration is stopped once there is an element that matches `predicate`. * - * @param {T[]} arr The array to iterate over. + * @template T + * @param {ArrayLike | Record | null | undefined} source The source to iterate over. * @param {((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string} [predicate=identity] The function invoked per iteration. * If a property name or an object is provided it will be used to create a predicate function. * @returns {boolean} Returns `true` if any element passes the predicate check, else `false`. @@ -118,12 +182,27 @@ export function some( * * some([{ a: 1 }, { a: 2 }, { a: 3 }], 'a'); * // => true + * + * some({ a: 1, b: 2, c: 3 }, n => n % 2 === 0); + * // => true + * + * some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, { name: 'Bob' }); + * // => true + * + * some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, ['name', 'Alice']); + * // => true + * + * some({ a: { id: 1, name: 'Alice' }, b: { id: 2, name: 'Bob' } }, 'name'); + * // => true */ export function some( - arr: readonly T[] | null | undefined, + source: ArrayLike | Record | null | undefined, predicate?: ((item: T, index: number, arr: any) => unknown) | Partial | [keyof T, unknown] | string, guard?: unknown ): boolean { + if (!source) { + return false; + } if (guard != null) { predicate = undefined; } @@ -132,26 +211,38 @@ export function some( predicate = identity; } - if (!Array.isArray(arr)) { - return false; - } + const values = Array.isArray(source) ? source : Object.values(source); switch (typeof predicate) { case 'function': { - return arr.some(predicate); + if (!Array.isArray(source)) { + const keys = Object.keys(source) as Array; + + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const value = source[key]; + + if (predicate(value as T, key as number, source)) { + return true; + } + } + + return false; + } + return values.some(predicate); } case 'object': { if (Array.isArray(predicate) && predicate.length === 2) { const key = predicate[0]; const value = predicate[1]; - return arr.some(matchesProperty(key, value)); + return values.some(matchesProperty(key, value)); } else { - return arr.some(matches(predicate)); + return values.some(matches(predicate)); } } case 'string': { - return arr.some(property(predicate)); + return values.some(property(predicate)); } } }