diff --git a/benchmarks/performance/isMap.bench.ts b/benchmarks/performance/isMap.bench.ts index 912ba9aa9..b8f0435dc 100644 --- a/benchmarks/performance/isMap.bench.ts +++ b/benchmarks/performance/isMap.bench.ts @@ -1,8 +1,10 @@ import { bench, describe } from 'vitest'; import { isMap as isMapToolkit_ } from 'es-toolkit'; +import { isMap as isMapToolkitCompat_ } from 'es-toolkit/compat' import { isMap as isMapLodash_ } from 'lodash'; const isMapToolkit = isMapToolkit_; +const isMapToolkitCompat = isMapToolkitCompat_ ; const isMapLodash = isMapLodash_; describe('isMap', () => { @@ -15,6 +17,15 @@ describe('isMap', () => { isMapToolkit(null); }); + bench('es-toolkit/compat/isMap', () => { + isMapToolkitCompat(new Map()); + isMapToolkitCompat(new Map([['key', 'value']])); + isMapToolkitCompat(new WeakMap()); + isMapToolkitCompat([]); + isMapToolkitCompat({}); + isMapToolkitCompat(null); + }); + bench('lodash/isMap', () => { isMapLodash(new Map()); isMapLodash(new Map([['key', 'value']])); diff --git a/benchmarks/performance/isSet.bench.ts b/benchmarks/performance/isSet.bench.ts index 7d8c95348..3da28499c 100644 --- a/benchmarks/performance/isSet.bench.ts +++ b/benchmarks/performance/isSet.bench.ts @@ -1,8 +1,10 @@ import { bench, describe } from 'vitest'; import { isSet as isSetToolkit_ } from 'es-toolkit'; +import { isSet as isSetToolkitCompat_ } from 'es-toolkit/compat'; import { isSet as isSetLodash_ } from 'lodash'; const isSetToolkit = isSetToolkit_; +const isSetToolkitCompat = isSetToolkitCompat_; const isSetLodash = isSetLodash_; describe('isSet', () => { @@ -14,6 +16,14 @@ describe('isSet', () => { isSetToolkit(null); }); + bench('es-toolkit/isSetCompat', () => { + isSetToolkitCompat(new Set()); + isSetToolkitCompat(new WeakSet()); + isSetToolkitCompat([]); + isSetToolkitCompat({}); + isSetToolkitCompat(null); + }); + bench('lodash/isSet', () => { isSetLodash(new Set()); isSetLodash(new WeakSet()); diff --git a/src/compat/_internal/weakMap.ts b/src/compat/_internal/weakMap.ts new file mode 100644 index 000000000..5080b9a2e --- /dev/null +++ b/src/compat/_internal/weakMap.ts @@ -0,0 +1 @@ +export const weakMap = new WeakMap(); diff --git a/src/compat/_internal/weakSet.ts b/src/compat/_internal/weakSet.ts new file mode 100644 index 000000000..529a96531 --- /dev/null +++ b/src/compat/_internal/weakSet.ts @@ -0,0 +1 @@ +export const weakSet = new WeakSet(); diff --git a/src/compat/index.ts b/src/compat/index.ts index e3656f7b6..095cc3526 100644 --- a/src/compat/index.ts +++ b/src/compat/index.ts @@ -92,6 +92,8 @@ export { isError } from './predicate/isError.ts'; export { isFinite } from './predicate/isFinite.ts'; export { isTypedArray } from './predicate/isTypedArray.ts'; export { isMatch } from './predicate/isMatch.ts'; +export { isMap } from './predicate/isMap.ts'; +export { isSet } from './predicate/isSet.ts'; export { isRegExp } from './predicate/isRegExp.ts'; export { isString } from './predicate/isString.ts'; export { matches } from './predicate/matches.ts'; diff --git a/src/compat/predicate/isMap.spec.ts b/src/compat/predicate/isMap.spec.ts new file mode 100644 index 000000000..4a780aaa1 --- /dev/null +++ b/src/compat/predicate/isMap.spec.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from 'vitest'; +import { isMap } from './isMap'; +import { args } from '../_internal/args'; +import { falsey } from '../_internal/falsey'; +import { slice } from '../_internal/slice'; +import { stubFalse } from '../_internal/stubFalse'; +import { symbol } from '../_internal/symbol'; +import { weakMap } from '../_internal/weakMap'; + +describe('isMap', () => { + it('should return `true` for maps', () => { + expect(isMap(new Map())).toBe(true); + }); + + it('returns false if the value is not a Map', () => { + const expected = falsey.map(() => stubFalse()); + + const actual = falsey.map((value, index) => (index ? isMap(value) : isMap())); + + expect(actual).toEqual(expected); + + expect(isMap(args)).toBe(false); + expect(isMap([1, 2, 3])).toBe(false); + expect(isMap(true)).toBe(false); + expect(isMap(new Date())).toBe(false); + expect(isMap(new Error())).toBe(false); + expect(isMap(slice)).toBe(false); + expect(isMap({ a: 1 })).toBe(false); + expect(isMap(1)).toBe(false); + expect(isMap(/x/)).toBe(false); + expect(isMap('a')).toBe(false); + expect(isMap(symbol)).toBe(false); + expect(isMap(weakMap)).toBe(false); + }); + + it('should work for objects with a non-function `constructor` (test in IE 11)', () => { + const expected = falsey.map(() => stubFalse()); + + const actual = falsey.map(value => isMap({ constructor: value })); + + expect(actual).toEqual(expected); + }); +}); diff --git a/src/compat/predicate/isMap.ts b/src/compat/predicate/isMap.ts new file mode 100644 index 000000000..eec1e13c1 --- /dev/null +++ b/src/compat/predicate/isMap.ts @@ -0,0 +1,23 @@ +import { isMap as isMapToolKit } from '../../predicate'; + +/** + * Checks if a given value is `Map`. + * + * This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `Map`. + * + * @param {unknown} value The value to check if it is a `Map`. + * @returns {value is Map} Returns `true` if `value` is a `Map`, else `false`. + * + * @example + * const value1 = new Map(); + * const value2 = new Set(); + * const value3 = new WeakMap(); + * + * console.log(isMap(value1)); // true + * console.log(isMap(value2)); // false + * console.log(isMap(value3)); // false + */ + +export function isMap(value?: unknown): value is Map { + return isMapToolKit(value); +} diff --git a/src/compat/predicate/isSet.spec.ts b/src/compat/predicate/isSet.spec.ts new file mode 100644 index 000000000..1323602e2 --- /dev/null +++ b/src/compat/predicate/isSet.spec.ts @@ -0,0 +1,43 @@ +import { describe, expect, it } from 'vitest'; +import { isSet } from './isSet'; +import { args } from '../_internal/args'; +import { falsey } from '../_internal/falsey'; +import { slice } from '../_internal/slice'; +import { stubFalse } from '../_internal/stubFalse'; +import { symbol } from '../_internal/symbol'; +import { weakSet } from '../_internal/weakSet'; + +describe('isSet', () => { + it('should return `true` for sets', () => { + expect(isSet(new Set())).toBe(true); + }); + + it('should return `false` for non-sets', () => { + const expected = falsey.map(() => stubFalse()); + + const actual = falsey.map((value, index) => (index ? isSet(value) : isSet())); + + expect(actual).toEqual(expected); + + expect(isSet(args)).toBe(false); + expect(isSet([1, 2, 3])).toBe(false); + expect(isSet(true)).toBe(false); + expect(isSet(new Date())).toBe(false); + expect(isSet(new Error())).toBe(false); + expect(isSet(slice)).toBe(false); + expect(isSet({ a: 1 })).toBe(false); + expect(isSet(1)).toBe(false); + expect(isSet(/x/)).toBe(false); + expect(isSet('a')).toBe(false); + expect(isSet(symbol)).toBe(false); + expect(isSet(weakSet)).toBe(false); + }); + + it('should work for objects with a non-function `constructor` (test in IE 11)', () => { + const expected = falsey.map(() => stubFalse()); + + const actual = falsey.map(value => isSet({ constructor: value })); + + expect(actual).toEqual(expected); + }); +}); diff --git a/src/compat/predicate/isSet.ts b/src/compat/predicate/isSet.ts new file mode 100644 index 000000000..206342eb5 --- /dev/null +++ b/src/compat/predicate/isSet.ts @@ -0,0 +1,23 @@ +import { isSet as isSetToolkit } from '../../predicate/isSet.ts'; + +/** + * Checks if a given value is `Set`. + * + * This function can also serve as a type predicate in TypeScript, narrowing the type of the argument to `Set`. + * + * @param {unknown} value The value to check if it is a `Set`. + * @returns {value is Set} Returns `true` if `value` is a `Set`, else `false`. + * + * @example + * const value1 = new Set(); + * const value2 = new Map(); + * const value3 = new WeakSet(); + * + * console.log(isSet(value1)); // true + * console.log(isSet(value2)); // false + * console.log(isSet(value3)); // false + */ + +export function isSet(value?: unknown): value is Set { + return isSetToolkit(value); +}