Skip to content
10 changes: 7 additions & 3 deletions docs/ja/reference/array/difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const result = difference(firstArr, secondArr);

2つの配列の差集合を求めたい場合は、`difference` を使用してください。最初の配列にのみ存在し、2番目の配列には存在しない要素で構成された新しい配列が返されます。

TypeScript でリテラルまたは特定の値を 2 番目の配列に渡すと、返り値の型が `Exclude<T, U>` を使って自動的に絞り込まれ、より精密な型推論が得られます。

```typescript
import { difference } from 'es-toolkit/array';

Expand All @@ -20,13 +22,15 @@ const array1 = [1, 2, 3, 4, 5];
const array2 = [2, 4];
difference(array1, array2);
// 戻り値: [1, 3, 5]
// 型: (1 | 3 | 5)[]
// 2と4は両方の配列に存在するため除外されます。

// 文字列配列の差集合を求めます。
const colors1 = ['red', 'blue', 'green'];
const colors2 = ['blue', 'yellow'];
difference(colors1, colors2);
// 戻り値: ['red', 'green']
// 型: ('red' | 'green')[]
```

空の配列との差集合は元の配列と同じです。
Expand All @@ -40,12 +44,12 @@ difference([], [1, 2, 3]); // []

#### パラメータ

- `firstArr` (`T[]`): 差集合を求める基準配列。
- `secondArr` (`T[]`): 最初の配列から除外する要素を含む配列。
- `firstArr` (`readonly T[]`): 差集合を求める基準配列。
- `secondArr` (`readonly U[]`): 最初の配列から除外する要素を含む配列。2番目の配列をリテラル値で定義すると、返り値の型が自動的に `Exclude<T, U>[]` に絞り込まれます

#### 戻り値

(`T[]`): 最初の配列にのみ存在し、2番目の配列には存在しない要素で構成された新しい配列。
(`Exclude<T, U>[]`): 最初の配列にのみ存在し、2番目の配列には存在しない要素で構成された新しい配列。2番目の配列が広い型で記述されている場合、返り値の型は `T[]` にフォールバックします

## パフォーマンス比較

Expand Down
8 changes: 6 additions & 2 deletions docs/ja/reference/array/without.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@ const filtered = without(arr, ...values);

配列から不要な特定の値を削除したい場合は `without` を使用してください。元の配列は変更されず、指定した値が削除された新しい配列が返されます。

リテラル値を渡した場合は、TypeScript の型推論が強化され、`Exclude<T, V>` を使って返り値の型が自動的に絞り込まれます。

```typescript
import { without } from 'es-toolkit/array';

// 数値配列から特定の値を削除します。
without([1, 2, 3, 4, 5], 2, 4);
// Returns: [1, 3, 5]
// 型: (1 | 3 | 5)[]

// 文字列配列から特定の値を削除します。
without(['a', 'b', 'c', 'a'], 'a');
// Returns: ['b', 'c']
// 型: ('b' | 'c')[]
```

`NaN` 値も正しく処理されます。
Expand All @@ -36,8 +40,8 @@ without([1, NaN, 3, NaN, 5], NaN);
#### パラメータ

- `arr` (`readonly T[]`): 値を削除する配列です。
- `values` (`...T[]`): 配列から削除する値です。
- `values` (`...V[]`): 配列から削除する値です。リテラル値を使用すると、返り値の型が自動的に `Exclude<T, V>[]` に絞り込まれます

#### 戻り値

(`T[]`): 指定された値が削除された新しい配列を返します。
(`Exclude<T, V>[]`): 指定された値が削除された新しい配列を返します。特定のリテラル値を渡さない場合、返り値の型は `T[]` にフォールバックします
10 changes: 7 additions & 3 deletions docs/ko/reference/array/difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const result = difference(firstArr, secondArr);

두 배열의 차집합을 구하고 싶을 때 `difference`를 사용하세요. 첫 번째 배열에만 있고 두 번째 배열에는 없는 요소들로 이루어진 새 배열이 반환돼요.

두 번째 배열에 리터럴이나 구체적인 값을 넘기면 TypeScript의 타입 추론이 강화돼서 `Exclude<T, U>`를 활용한 반환 타입이 자동으로 좁혀져요.

```typescript
import { difference } from 'es-toolkit/array';

Expand All @@ -20,13 +22,15 @@ const array1 = [1, 2, 3, 4, 5];
const array2 = [2, 4];
difference(array1, array2);
// Returns: [1, 3, 5]
// 타입: (1 | 3 | 5)[]
// 2와 4는 두 배열 모두에 있어서 제외돼요.

// 문자열 배열의 차집합을 구해요.
const colors1 = ['red', 'blue', 'green'];
const colors2 = ['blue', 'yellow'];
difference(colors1, colors2);
// Returns: ['red', 'green']
// 타입: ('red' | 'green')[]
```

빈 배열과의 차집합은 원래 배열과 같아요.
Expand All @@ -40,12 +44,12 @@ difference([], [1, 2, 3]); // []

#### 파라미터

- `firstArr` (`T[]`): 차집합을 구할 기준 배열이에요.
- `secondArr` (`T[]`): 첫 번째 배열에서 제외할 요소들을 포함한 배열이에요.
- `firstArr` (`readonly T[]`): 차집합을 구할 기준 배열이에요.
- `secondArr` (`readonly U[]`): 첫 번째 배열에서 제외할 요소들을 포함한 배열이에요. 두 번째 배열을 리터럴 값으로 정의하면 반환 타입이 자동으로 `Exclude<T, U>[]`로 좁혀져요.

#### 반환 값

(`T[]`): 첫 번째 배열에만 있고 두 번째 배열에는 없는 요소들로 이루어진 새 배열이에요.
(`Exclude<T, U>[]`): 첫 번째 배열에만 있고 두 번째 배열에는 없는 요소들로 이루어진 새 배열이에요. 두 번째 배열을 넓은 타입으로 선언하면 반환 타입은 `T[]`로 유지돼요.

## 성능 비교

Expand Down
8 changes: 5 additions & 3 deletions docs/ko/reference/array/without.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ const filtered = without(arr, ...values);

### `without(arr, ...values)`

배열에서 원하지 않는 특정 값들을 제거하고 싶을 때 `without`을 사용하세요. 원본 배열은 수정되지 않고, 지정한 값들이 제거된 새 배열이 반환돼요.
배열에서 원하지 않는 특정 값들을 제거하고 싶을 때 `without`을 사용하세요. 원본 배열은 수정되지 않고, 지정한 값들이 제외된 새 배열이 반환돼요. 리터럴 값을 넘기면 TypeScript의 타입 추론이 강화돼서 `Exclude<T, V>`를 활용해 반환 타입이 자동으로 좁혀져요.

```typescript
import { without } from 'es-toolkit/array';

// 숫자 배열에서 특정 값들을 제거해요.
without([1, 2, 3, 4, 5], 2, 4);
// Returns: [1, 3, 5]
// 타입: (1 | 3 | 5)[]

// 문자열 배열에서 특정 값을 제거해요.
without(['a', 'b', 'c', 'a'], 'a');
// Returns: ['b', 'c']
// 타입: ('b' | 'c')[]
```

`NaN` 값도 올바르게 처리해요.
Expand All @@ -36,8 +38,8 @@ without([1, NaN, 3, NaN, 5], NaN);
#### 파라미터

- `arr` (`readonly T[]`): 값들을 제거할 배열이에요.
- `values` (`...T[]`): 배열에서 제거할 값들이에요.
- `values` (`...readonly V[]`):: 배열에서 제거할 값들이에요. 리터럴 값을 넘기면 반환 타입이 자동으로 `Exclude<T, V>[]`로 좁혀져요.

#### 반환 값

(`T[]`): 지정된 값들이 제거된 새 배열을 반환해요.
(`Exclude<T, V>[]`): 지정된 값들이 제외된 새 배열을 반환해요. 특정 리터럴 값을 넘기지 않으면 반환 타입은 `T[]`로 유지돼요.
13 changes: 10 additions & 3 deletions docs/reference/array/difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const result = difference(firstArr, secondArr);

Use `difference` when you want to find the difference between two arrays. A new array is returned containing elements that are only in the first array and not in the second array.

The function now provides enhanced TypeScript type inference —
when the second array contains literal or specific values,
the return type automatically narrows using `Exclude<T, U>` while maintaining backward compatibility.

```typescript
import { difference } from 'es-toolkit/array';

Expand All @@ -20,13 +24,15 @@ const array1 = [1, 2, 3, 4, 5];
const array2 = [2, 4];
difference(array1, array2);
// Returns: [1, 3, 5]
// Type: (1 | 3 | 5)[]
// 2 and 4 are excluded because they are in both arrays.

// Find the difference of string arrays.
const colors1 = ['red', 'blue', 'green'];
const colors2 = ['blue', 'yellow'];
difference(colors1, colors2);
// Returns: ['red', 'green']
// Type: ('red' | 'green')[]
```

The difference with an empty array is the same as the original array.
Expand All @@ -40,12 +46,13 @@ difference([], [1, 2, 3]); // []

#### Parameters

- `firstArr` (`T[]`): The reference array to find the difference from.
- `secondArr` (`T[]`): The array containing elements to exclude from the first array.
- `firstArr` (`readonly T[]`): The reference array to find the difference from.
- `secondArr` (`readonly U[]`): The array containing elements to exclude from the first array. When the second array is defined with literal values, the return type is automatically narrowed to `Exclude<T, U>[]`.

#### Returns

(`T[]`): A new array containing elements that are only in the first array and not in the second array.
(`Exclude<T, U>[]`): A new array containing elements that are only in the first array and not in the second array.
If the second array is typed broadly, the return type falls back to T[].

## Performance Comparison

Expand Down
14 changes: 11 additions & 3 deletions docs/reference/array/without.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,22 @@ const filtered = without(arr, ...values);

Use `without` when you want to remove unwanted specific values from an array. The original array is not modified, and a new array with the specified values removed is returned.

```typescript
The function also provides enhanced TypeScript type inference —
when literal values are passed, the return type automatically narrows using `Exclude<T, V>`.

```
import { without } from 'es-toolkit/array';

// Remove specific values from a number array.
without([1, 2, 3, 4, 5], 2, 4);
// Returns: [1, 3, 5]
// Type: (1 | 3 | 5)[]

// Remove specific value from a string array.
without(['a', 'b', 'c', 'a'], 'a');
// Returns: ['b', 'c']
// Type: ('b' | 'c')[]

```

It also handles `NaN` values correctly.
Expand All @@ -36,8 +42,10 @@ without([1, NaN, 3, NaN, 5], NaN);
#### Parameters

- `arr` (`readonly T[]`): The array from which to remove values.
- `values` (`...T[]`): The values to remove from the array.
- `values` (`...V[]`): The values to remove from the array.
When literal values are used, the return type is automatically narrowed to `Exclude<T, V>[]`.

#### Returns

(`T[]`): Returns a new array with the specified values removed.
(`Exclude<T, V>[]`): Returns a new array with the specified values removed.
If no specific literal values are provided, the return type falls back to `T[]`.
13 changes: 10 additions & 3 deletions docs/zh_hans/reference/array/difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const result = difference(firstArr, secondArr);

当您想求两个数组的差集时,请使用 `difference`。返回一个新数组,包含只在第一个数组中存在而第二个数组中不存在的元素。

该函数现在提供增强的 TypeScript 类型推断 ——
当第二个数组包含字面量或具体值时,
返回类型会在保持向后兼容的同时自动缩小为 `Exclude<T, U>`。

```typescript
import { difference } from 'es-toolkit/array';

Expand All @@ -20,13 +24,15 @@ const array1 = [1, 2, 3, 4, 5];
const array2 = [2, 4];
difference(array1, array2);
// 返回: [1, 3, 5]
// 类型: (1 | 3 | 5)[]
// 2 和 4 在两个数组中都存在,所以被排除。

// 求字符串数组的差集。
const colors1 = ['red', 'blue', 'green'];
const colors2 = ['blue', 'yellow'];
difference(colors1, colors2);
// 返回: ['red', 'green']
// 类型: ('red' | 'green')[]
```

与空数组的差集等于原数组。
Expand All @@ -40,12 +46,13 @@ difference([], [1, 2, 3]); // []

#### 参数

- `firstArr` (`T[]`): 作为差集基准的数组。
- `secondArr` (`T[]`): 包含要从第一个数组中排除的元素的数组。
- `firstArr` (`readonly T[]`): 作为差集基准的数组。
- `secondArr` (`readonly U[]`): 包含要从第一个数组中排除的元素的数组。当第二个数组使用字面量值时,返回类型会自动缩小为 `Exclude<T, U>[]`

#### 返回值

(`T[]`): 包含只在第一个数组中存在而第二个数组中不存在的元素的新数组。
(`Exclude<T, U>[]`): 包含只在第一个数组中存在而第二个数组中不存在的元素的新数组。
如果第二个数组类型较宽,返回类型会回退为 `T[]`。

## 性能对比

Expand Down
11 changes: 9 additions & 2 deletions docs/zh_hans/reference/array/without.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@ const filtered = without(arr, ...values);

当您想从数组中删除不需要的特定值时,请使用 `without`。原数组不会被修改,返回已删除指定值的新数组。

该函数还提供增强的 TypeScript 类型推断 —
当传递字面量值时,返回类型会自动使用 `Exclude<T, V>` 进行缩小。

```typescript
import { without } from 'es-toolkit/array';

// 从数字数组中删除特定值。
without([1, 2, 3, 4, 5], 2, 4);
// Returns: [1, 3, 5]
// Type: (1 | 3 | 5)[]

// 从字符串数组中删除特定值。
without(['a', 'b', 'c', 'a'], 'a');
// Returns: ['b', 'c']
// Type: ('b' | 'c')[]
```

也能正确处理 `NaN` 值。
Expand All @@ -36,8 +41,10 @@ without([1, NaN, 3, NaN, 5], NaN);
#### 参数

- `arr` (`readonly T[]`): 要删除值的数组。
- `values` (`...T[]`): 要从数组中删除的值。
- `values` (`...V[]`): 要从数组中删除的值。
当使用字面量值时,返回类型会自动缩小为 `Exclude<T, V>[]`。

#### 返回值

(`T[]`): 返回已删除指定值的新数组。
(`Exclude<T, V>[]`): 返回已删除指定值的新数组。
如果未提供特定的字面量值,返回类型将回退为 `T[]`。
29 changes: 22 additions & 7 deletions src/array/difference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
* that are present in the first array but not in the second array. It effectively
* filters out any elements from the first array that also appear in the second array.
*
* @template T
* @param {T[]} firstArr - The array from which to derive the difference. This is the primary array
*
* @template T The type of elements in the first array.
* @template U A subtype of T representing the values to exclude.
* @param {readonly T[]} firstArr - The array from which to derive the difference. This is the primary array
* from which elements will be compared and filtered.
* @param {T[]} secondArr - The array containing elements to be excluded from the first array.
* @param {readonly U[]} secondArr - The array containing elements to be excluded from the first array.
* Each element in this array will be checked against the first array, and if a match is found,
* that element will be excluded from the result.
* @returns {T[]} A new array containing the elements that are present in the first array but not
* @returns {Exclude<T, U>[]} A new array containing the elements that are present in the first array but not
* in the second array.
*
* @example
Expand All @@ -20,8 +22,21 @@
* const result = difference(array1, array2);
* // result will be [1, 3, 5] since 2 and 4 are in both arrays and are excluded from the result.
*/
export function difference<T>(firstArr: readonly T[], secondArr: readonly T[]): T[] {
const secondSet = new Set(secondArr);

return firstArr.filter(item => !secondSet.has(item));
// When the second array is empty → keep T[]
export function difference<T>(firstArr: readonly T[], secondArr: readonly []): T[];

// When the second array contains specific values → narrow to Exclude<T, U>[]
export function difference<T, U extends T>(firstArr: readonly T[], secondArr: readonly U[]): Array<Exclude<T, U>>;

// Fallback overload for backward compatibility → return T[]
export function difference<T>(firstArr: readonly T[], secondArr: readonly T[]): T[];

// Implementation — same parameter style as the original version
export function difference<T, U extends T = never>(
firstArr: readonly T[],
secondArr: readonly T[]
): Array<Exclude<T, U>> {
const secondSet = new Set(secondArr);
return firstArr.filter(item => !secondSet.has(item)) as Array<Exclude<T, U>>;
}
25 changes: 19 additions & 6 deletions src/array/without.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { difference } from './difference.ts';
/**
* Creates an array that excludes all specified values.
*
* It correctly excludes `NaN`, as it compares values using [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero).
* It correctly excludes `NaN`, as it compares values using
* [SameValueZero](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero).
*
* @template T The type of elements in the array.
* @param {T[]} array - The array to filter.
* @param {...T[]} values - The values to exclude.
* @returns {T[]} A new array without the specified values.
* @template V A subtype of T representing the values to exclude.
* @param {readonly T[]} array - The array to filter.
* @param {...V[]} values - The values to exclude.
* @returns {Exclude<T, V>[]} A new array without the specified values.
*
* @example
* // Removes the specified values from the array
Expand All @@ -20,6 +22,17 @@ import { difference } from './difference.ts';
* without(['a', 'b', 'c', 'a'], 'a');
* // Returns: ['b', 'c']
*/
export function without<T>(array: readonly T[], ...values: T[]): T[] {
return difference(array, values);

// No values provided → return type stays as T[]
export function without<T>(array: readonly T[], ...values: []): T[];

// Literal or specific values provided → return Exclude<T, V>[]
export function without<T, V extends T>(array: readonly T[], ...values: V[]): Array<Exclude<T, V>>;

// Broad fallback overload for full backward compatibility
export function without<T>(array: readonly T[], ...values: T[]): T[];

// Implementation — same runtime logic as before
export function without<T, V extends T = never>(array: readonly T[], ...values: T[]): Array<Exclude<T, V>> {
return difference(array, values) as Array<Exclude<T, V>>;
}