fix(ary, unary): Fix guard in ary & unary, add Korean docs
Some checks are pending
CI / codecov (push) Waiting to run
Release / release (push) Waiting to run

This commit is contained in:
raon0211 2024-08-07 18:59:50 +09:00
parent d7d3cd28a2
commit b2427e1f4b
10 changed files with 168 additions and 44 deletions

View File

@ -131,6 +131,8 @@ function sidebar(): DefaultTheme.Sidebar {
{ text: 'negate', link: '/ko/reference/function/negate' },
{ text: 'once', link: '/ko/reference/function/once' },
{ text: 'noop', link: '/ko/reference/function/noop' },
{ text: 'ary', link: '/reference/function/ary' },
{ text: 'unary', link: '/reference/function/unary' },
],
},
{

View File

@ -0,0 +1,37 @@
# ary
인자를 최대 `n`개까지만 제한해서 받는 새로운 함수를 만들어요. 그 이상으로 주어진 인자는 무시해요.
## 인터페이스
```typescript
function ary<F extends (...args: any[]) => any>(
func: F,
n: number
): (...args: any[]) => ReturnType<F>;
```
### 파라미터
- `func` (`F`): 인자를 받는 것을 제한할 함수.
- `n` (`number`, 선택): 최대로 받을 인자의 숫자.
### 반환 값
(`(...args: any[]) => ReturnType<F>`): 받을 수 있는 인자의 숫자가 제한된 함수.
## 예시
```typescript
import { ary } from 'es-toolkit/function';
function fn(a, b, c) {
console.log(arguments);
}
ary(fn, 2)(1, 2, 3); // [Arguments] { '0': 1, '1': 2 }
ary(fn); // [Arguments] { '0': 1, '1': 2, '2': 3 }
ary(fn, -1); // [Arguments] {}
ary(fn, 1.5); // [Arguments] { '0': 1 }
ary(fn, 2, {}); // [Arguments] { '0': 1, '1': 2, '2': 3 }
```

View File

@ -0,0 +1,29 @@
# unary
인자를 최대 1개만 받는 새로운 함수를 만들어요. 그 이상으로 주어진 인자는 무시해요.
## 인터페이스
```typescript
function unary<F extends (...args: any[]) => any>(func: F): (...args: any[]) => ReturnType<F>;
```
### 파라미터
- `func` (`F`): 인자를 1개만 받도록 할 함수
### 반환 값
(`(...args: any[]) => ReturnType<F>`): 인자를 최대 1개만 받도록 한 함수
## 예시
```typescript
import { unary } from 'es-toolkit/function';
function fn(a, b, c) {
console.log(arguments);
}
unary(fn)(1, 2, 3); // [Arguments] { '0': 1 }
```

View File

@ -7,8 +7,7 @@ Creates a function that invokes func, with up to n arguments, ignoring any addit
```typescript
function ary<F extends (...args: any[]) => any>(
func: F,
n: number = func.length,
guard?: any
n: number
): (...args: any[]) => ReturnType<F>;
```
@ -16,7 +15,6 @@ function ary<F extends (...args: any[]) => any>(
- `func` (`F`): The function to cap arguments for.
- `n` (`number`, optional): The arity cap, defaulting to the number of parameters of `func`. Negative numbers will be treated as `0`, and decimals will be rounded down.
- `guard` (`any`, optional): Enables use as an iteratee for methods like `map`.
### Returns

View File

@ -0,0 +1,73 @@
import { describe, expect, it } from 'vitest';
import { ary } from './ary';
describe('ary', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function fn(_a: unknown, _b: unknown, _c: unknown) {
// eslint-disable-next-line prefer-rest-params
return Array.from(arguments);
}
it('should cap the number of arguments provided to `func`', () => {
const actual = ['6', '8', '10'].map(ary(parseInt, 1));
expect(actual).toEqual([6, 8, 10]);
const capped = ary(fn, 2);
expect(capped('a', 'b', 'c', 'd')).toEqual(['a', 'b']);
});
it('should use `func.length` if `n` is not given', () => {
const capped = ary(fn);
expect(capped('a', 'b', 'c', 'd')).toEqual(['a', 'b', 'c']);
});
it('should treat a negative `n` as `0`', () => {
const capped = ary(fn, -1);
expect(capped('a', 'b', 'c', 'd')).toEqual([]);
});
it('should coerce `n` to an integer', () => {
const values = ['1', 1.6, 'xyz'];
const expected = [['a'], ['a'], []];
const actual = values.map((n: any) => {
const capped = ary(fn, n);
return capped('a', 'b');
});
expect(actual).toEqual(expected);
});
it('should not force a minimum argument count', () => {
const args = ['a', 'b', 'c'];
const capped = ary(fn, 3);
const expected = args.map((arg, index) => args.slice(0, index));
// eslint-disable-next-line prefer-spread
const actual = expected.map(array => capped.apply(undefined, array));
expect(actual).toEqual(expected);
});
it('should use `this` binding of function', () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const capped = ary(function (this: unknown, _a: unknown, _b: unknown) {
return this;
}, 1);
const object = { capped: capped };
expect(object.capped()).toBe(object);
});
it('should use the existing `ary` if smaller', () => {
const capped = ary(ary(fn, 1), 2);
expect(capped('a', 'b', 'c', 'd')).toEqual(['a']);
});
it('should work as an iteratee for methods like `_.map`', () => {
const funcs = [fn].map(ary);
const actual = funcs[0]('a', 'b', 'c');
expect(actual).toEqual(['a', 'b', 'c']);
});
});

View File

@ -0,0 +1,21 @@
import { ary as aryToolkit } from '../../function/ary.ts';
/**
* Creates a function that invokes func, with up to n arguments, ignoring any additional arguments.
*
* @template F - The type of the function.
* @param {F} func - The function to cap arguments for.
* @param {number} n - The arity cap.
* @returns {(...args: any[]) => ReturnType<F>} Returns the new capped function.
*/
export function ary<F extends (...args: any[]) => any>(func: F, n: number = func.length, guard?: unknown): ((...args: any[]) => ReturnType<F>) {
if (guard) {
n = func.length;
}
if (Number.isNaN(n) || n < 0) {
n = 0;
}
return aryToolkit(func, n);
};

View File

@ -32,7 +32,9 @@ export { flatten } from './array/flatten.ts';
export { flattenDeep } from './array/flattenDeep.ts';
export { flattenDepth } from './array/flattenDepth.ts';
export { zipObjectDeep } from './array/zipObjectDeep.ts';
export { head as first } from '../index.ts';
export { head as first } from '../array/head.ts';
export { ary } from './function/ary.ts';
export { get } from './object/get.ts';
export { set } from './object/set.ts';

View File

@ -16,28 +16,6 @@ describe('ary', () => {
expect(capped('a', 'b', 'c', 'd')).toEqual(['a', 'b']);
});
it('should use `func.length` if `n` is not given', () => {
const capped = ary(fn);
expect(capped('a', 'b', 'c', 'd')).toEqual(['a', 'b', 'c']);
});
it('should treat a negative `n` as `0`', () => {
const capped = ary(fn, -1);
expect(capped('a', 'b', 'c', 'd')).toEqual([]);
});
it('should coerce `n` to an integer', () => {
const values = ['1', 1.6, 'xyz'];
const expected = [['a'], ['a'], []];
const actual = values.map((n: any) => {
const capped = ary(fn, n);
return capped('a', 'b');
});
expect(actual).toEqual(expected);
});
it('should not force a minimum argument count', () => {
const args = ['a', 'b', 'c'];
const capped = ary(fn, 3);
@ -63,11 +41,4 @@ describe('ary', () => {
const capped = ary(ary(fn, 1), 2);
expect(capped('a', 'b', 'c', 'd')).toEqual(['a']);
});
it('should work as an iteratee for methods like `_.map`', () => {
const funcs = [fn].map(ary);
const actual = funcs[0]('a', 'b', 'c');
expect(actual).toEqual(['a', 'b', 'c']);
});
});

View File

@ -1,22 +1,13 @@
/**
* Creates a function that invokes func, with up to n arguments, ignoring any additional arguments.
*
*
* @template F - The type of the function.
* @param {F} func - The function to cap arguments for.
* @param {number} n - The arity cap.
* @param {any} guard - Enables use as an iteratee for methods like `map`.
* @returns {(...args: any[]) => ReturnType<F>} Returns the new capped function.
*/
export const ary = <F extends (...args: any[]) => any>(
func: F,
n: number = func.length,
guard?: any
): ((...args: any[]) => ReturnType<F>) => {
n = guard ? func.length : Number.parseInt(n.toString());
if (Number.isNaN(n) || n < 0) {
n = 0;
}
export function ary<F extends (...args: any[]) => any>(func: F, n: number): ((...args: any[]) => ReturnType<F>) {
return function (this: any, ...args: Parameters<F>) {
return func.apply(this, args.slice(0, n));
};

View File

@ -7,6 +7,6 @@ import { ary } from './ary.ts';
* @param {F} func - The function to cap arguments for.
* @returns {(...args: any[]) => ReturnType<F>} Returns the new capped function.
*/
export const unary = <F extends (...args: any[]) => any>(func: F): ((...args: any[]) => ReturnType<F>) => {
export function unary<F extends (...args: any[]) => any>(func: F): ((...args: any[]) => ReturnType<F>) {
return ary(func, 1);
};