Skip to content
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
11 changes: 11 additions & 0 deletions bench/isPrimitive.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { bench } from 'vitest';

import { isPrimitive } from '../src/predicate/isPrimitive.js';

import type { Primitive } from '../src/index.js';

const data: Primitive[] = ['string', 1, 1n, true, undefined, Symbol('test'), null];

bench('isPrimitive()', () => {
data.forEach(isPrimitive);
});
2 changes: 1 addition & 1 deletion bench/isPromiseLike.bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isObjectWith } from '../src/predicate/isObjectWith.js';
import { isPromiseLike } from '../src/predicate/isPromiseLike.js';

function isPromiseLike2<T>(input: unknown): input is PromiseLike<T> {
return isObjectWith(input, 'then') && isFunction(input.then) && input.then.length === 2;
return isObjectWith(input, ['then']) && isFunction(input.then) && input.then.length === 2;
}

const resolvedPromise = Promise.resolve();
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"devDependencies": {
"@commitlint/config-conventional": "^19.8.0",
"@commitlint/types": "^19.8.0",
"@types/node": "^22.13.11",
"@types/node": "^22.13.13",
"@vitest/coverage-v8": "^3.0.9",
"@webdeveric/eslint-config-ts": "^0.11.0",
"@webdeveric/prettier-config": "^0.3.0",
Expand All @@ -106,7 +106,7 @@
"rimraf": "^6.0.1",
"semantic-release": "^24.2.3",
"typescript": "^5.8.2",
"validate-package-exports": "^0.8.0",
"validate-package-exports": "^0.9.0",
"vitest": "^3.0.9"
},
"pnpm": {
Expand Down
399 changes: 189 additions & 210 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/assertion/assertIsObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { isObject } from '../predicate/isObject.js';

import { getError } from './getError.js';

import type { UnknownRecord } from '../types/records.js';

export function assertIsObject(
input: unknown,
error: string | Error = 'input is not an object',
): asserts input is object {
): asserts input is UnknownRecord {
if (!isObject(input)) {
throw getError(error);
}
Expand Down
6 changes: 2 additions & 4 deletions src/predicate/isAnyObjectWith.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { asArray } from '../asArray.js';

import { isAnyObject } from './isAnyObject.js';

/**
* Determine if `input` is an object and has the provided properties.
*/
export const isAnyObjectWith = <T, P extends PropertyKey>(
input: T,
properties: P | P[],
properties: P[],
): input is T & Record<P, unknown> => {
return isAnyObject(input) && asArray(properties).every((property) => property in input);
return isAnyObject(input) && properties.every((property) => property in input);
};
6 changes: 2 additions & 4 deletions src/predicate/isAnyObjectWithOwn.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { asArray } from '../asArray.js';

import { isAnyObject } from './isAnyObject.js';

/**
* Determine if `input` is an object and directly has the provided properties.
*/
export const isAnyObjectWithOwn = <T, P extends PropertyKey>(
input: T,
properties: P | P[],
properties: P[],
): input is T & Record<P, unknown> => {
return isAnyObject(input) && asArray(properties).every((property) => Object.hasOwn(input, property));
return isAnyObject(input) && properties.every((property) => Object.hasOwn(input, property));
};
4 changes: 3 additions & 1 deletion src/predicate/isObject.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { UnknownRecord } from '../types/records.js';

/**
* Determine if `input` is a non-null object and not an array.
*/
export const isObject = (input: unknown): input is object =>
export const isObject = (input: unknown): input is UnknownRecord =>
input !== null && typeof input === 'object' && !Array.isArray(input);
10 changes: 2 additions & 8 deletions src/predicate/isObjectWith.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { asArray } from '../asArray.js';

import { isObject } from './isObject.js';

/**
* Determine if `input` is an object and has the provided properties.
*/
export const isObjectWith = <T, P extends PropertyKey>(
input: T,
properties: P | P[],
): input is T & Record<P, unknown> => {
return isObject(input) && asArray(properties).every((property) => property in input);
};
export const isObjectWith = <T, P extends PropertyKey>(input: T, properties: P[]): input is T & Record<P, unknown> =>
isObject(input) && properties.every((property) => property in input);
22 changes: 7 additions & 15 deletions src/predicate/isPrimitive.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import { isBigInt } from './isBigInt.js';
import { isBoolean } from './isBoolean.js';
import { isNull } from './isNull.js';
import { isNumber } from './isNumber.js';
import { isString } from './isString.js';
import { isSymbol } from './isSymbol.js';
import { isUndefined } from './isUndefined.js';

import type { Primitive } from '../types/common.js';

export const isPrimitive = (input: unknown): input is Primitive =>
isString(input) ||
isNumber(input) ||
isBigInt(input) ||
isBoolean(input) ||
isUndefined(input) ||
isSymbol(input) ||
isNull(input);
input === null ||
typeof input === 'string' ||
typeof input === 'number' ||
typeof input === 'bigint' ||
typeof input === 'boolean' ||
typeof input === 'undefined' ||
typeof input === 'symbol';
10 changes: 6 additions & 4 deletions src/predicate/isPromiseFulfilledResult.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { isObjectWith } from './isObjectWith.js';
import { shape } from './factory/shape.js';
import { isUnknown } from './isUnknown.js';

export const isPromiseFulfilledResult = <T>(input: unknown): input is PromiseFulfilledResult<T> => {
return isObjectWith(input, 'status') && input.status === 'fulfilled';
};
export const isPromiseFulfilledResult = shape<PromiseFulfilledResult<unknown>>({
status: 'fulfilled',
value: isUnknown,
});
10 changes: 6 additions & 4 deletions src/predicate/isPromiseRejectedResult.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { isObjectWith } from './isObjectWith.js';
import { shape } from './factory/shape.js';
import { isAny } from './isAny.js';

export const isPromiseRejectedResult = (input: unknown): input is PromiseRejectedResult => {
return isObjectWith(input, ['status', 'reason']) && input.status === 'rejected';
};
export const isPromiseRejectedResult = shape<PromiseRejectedResult>({
status: 'rejected',
reason: isAny,
});
5 changes: 2 additions & 3 deletions test/predicate/isAnyObjectWith.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import { isAnyObjectWith } from '../../src/predicate/isAnyObjectWith.js';

describe('isAnyObjectWith()', () => {
it('Returns true for valid inputs', () => {
expect(isAnyObjectWith({ property: true }, 'property')).toBeTruthy();
expect(isAnyObjectWith({ property: true }, ['property'])).toBeTruthy();
expect(isAnyObjectWith({ name: 'Test Testerson', age: 100 }, ['name', 'age'])).toBeTruthy();
expect(isAnyObjectWith(['item'], 'length')).toBeTruthy();
expect(isAnyObjectWith(['item'], ['length'])).toBeTruthy();
});

it.each([null, false, 'string', Math.PI, Symbol()])('Returns false for invalid inputs', (item) => {
expect(isAnyObjectWith(item, 'property')).toBeFalsy();
expect(isAnyObjectWith(item, ['property'])).toBeFalsy();
});
});
5 changes: 2 additions & 3 deletions test/predicate/isAnyObjectWithOwn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { isAnyObjectWithOwn } from '../../src/predicate/isAnyObjectWithOwn.js';

describe('isAnyObjectWithOwn()', () => {
it('Returns true for valid inputs', () => {
expect(isAnyObjectWithOwn({ property: true }, 'property')).toBeTruthy();
expect(isAnyObjectWithOwn({ property: true }, ['property'])).toBeTruthy();
expect(isAnyObjectWithOwn({ name: 'Test Testerson', age: 100 }, ['name', 'age'])).toBeTruthy();
expect(isAnyObjectWithOwn(['item'], 'length')).toBeTruthy();
expect(isAnyObjectWithOwn(['item'], ['length'])).toBeTruthy();
});

it.each([
Expand All @@ -22,7 +22,6 @@ describe('isAnyObjectWithOwn()', () => {
},
),
])('Returns false for invalid inputs', (item) => {
expect(isAnyObjectWithOwn(item, 'property')).toBeFalsy();
expect(isAnyObjectWithOwn(item, ['property'])).toBeFalsy();
});
});
4 changes: 2 additions & 2 deletions test/predicate/isObjectWith.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import { isObjectWith } from '../../src/predicate/isObjectWith.js';

describe('isObjectWith()', () => {
it('Returns true for valid inputs', () => {
expect(isObjectWith({ property: true }, 'property')).toBeTruthy();
expect(isObjectWith({ property: true }, ['property'])).toBeTruthy();
expect(isObjectWith({ name: 'Test Testerson', age: 100 }, ['name', 'age'])).toBeTruthy();
});

it.each([[], null, false, 'string', Math.PI, Symbol()])('Returns false for invalid inputs', (item) => {
expect(isObjectWith(item, 'property')).toBeFalsy();
expect(isObjectWith(item, ['property'])).toBeFalsy();
expect(isObjectWith(item, ['property'])).toBeFalsy();
});
});