Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: deprecate NonNullObject and AnyObject #821

Merged
merged 2 commits into from
Oct 27, 2024
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
8 changes: 4 additions & 4 deletions packages/utilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@
- [`Awaitable`](#awaitable)
- [`Nullish`](#nullish)
- [`NonNullableProperties`](#nonnullableproperties)
- [`NonNullObject`](#nonnullobject)
- [`AnyObject`](#anyobject)
- [`NonNullObject`](#nonnullobject-deprecated)
- [`AnyObject`](#anyobject-deprecated)
- [`PickByValue`](#pickbyvalue)
- [`Mutable`](#mutable)
- [`StrictRequired`](#strictrequired)
Expand Down Expand Up @@ -766,7 +766,7 @@ interface Foo {
declare const foo: NonNullableProperties<Foo>;
```

##### `NonNullObject`
##### `NonNullObject` (deprecated)

A type that represents an object that is not `null` or `undefined`.

Expand All @@ -781,7 +781,7 @@ const bar: NonNullObject = null;
const baz: NonNullObject = undefined;
```

##### `AnyObject`
##### `AnyObject` (deprecated)

An object that can have any structure. Similar to `NonNullObject`, and to be used as an alternative if the aforementioned type leads to unexpected behaviors.

Expand Down
7 changes: 3 additions & 4 deletions packages/utilities/src/lib/getDeepObjectKeys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { isNullOrUndefinedOrEmpty } from './isNullOrUndefinedOrEmpty';
import type { AnyObject } from './types';

/**
* Flattens an object to a list of its keys, traversing deeply into nested objects and arrays of objects.
Expand All @@ -12,12 +11,12 @@ import type { AnyObject } from './types';
* @param options The options with which to customize the output of this function
* @returns An array of strings holding the keys of the object
*/
export function getDeepObjectKeys<T>(obj: AnyObject<T>, options?: GetDeepObjectKeysOptions): string[] {
export function getDeepObjectKeys(obj: object, options?: GetDeepObjectKeysOptions): string[] {
return [...getDeepObjectKeysGenerator(obj, options)];
}

function* getDeepObjectKeysGenerator<T>(
obj: AnyObject<T>,
function* getDeepObjectKeysGenerator(
obj: object,
{ arrayKeysIndexStyle = 'dotted' }: GetDeepObjectKeysOptions = { arrayKeysIndexStyle: 'dotted' }
): Generator<string> {
if (Array.isArray(obj)) {
Expand Down
6 changes: 1 addition & 5 deletions packages/utilities/src/lib/hasAtLeastOneKeyInObject.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { isNullish } from './isNullOrUndefined';
import type { NonNullObject } from './types';

/**
* Checks whether any of the {@link keys} are in the {@link obj}
Expand All @@ -14,9 +13,6 @@ import type { NonNullObject } from './types';
* console.log(hasAtLeastOneKeyInObject(obj, ['d'])); // false
* ```
*/
export function hasAtLeastOneKeyInObject<T extends NonNullObject, K extends PropertyKey>(
obj: T,
keys: readonly K[]
): obj is T & { [key in K]-?: unknown } {
export function hasAtLeastOneKeyInObject<T extends object, K extends PropertyKey>(obj: T, keys: readonly K[]): obj is T & { [key in K]-?: unknown } {
return !isNullish(obj) && keys.some((key) => Object.hasOwn(obj, key));
}
6 changes: 3 additions & 3 deletions packages/utilities/src/lib/isObject.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { Constructor, NonNullObject } from './types';
import type { Constructor } from './types';

/**
* Verify if the input is an object literal (or class).
* @param input The object to verify
* @param constructorType The type of the constructor of the object. Use this if you want a `class` of your choosing to pass the check as well.
*/
export function isObject(input: unknown, constructorType?: ObjectConstructor): input is NonNullObject;
export function isObject(input: unknown, constructorType?: ObjectConstructor): input is object;
export function isObject<T extends Constructor<unknown>>(input: unknown, constructorType: T): input is InstanceType<T>;
export function isObject<T extends Constructor<unknown> = ObjectConstructor>(input: unknown, constructorType?: T): input is NonNullObject {
export function isObject<T extends Constructor<unknown> = ObjectConstructor>(input: unknown, constructorType?: T): input is object {
return typeof input === 'object' && input ? input.constructor === (constructorType ?? Object) : false;
}
6 changes: 3 additions & 3 deletions packages/utilities/src/lib/mergeDefault.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { deepClone } from './deepClone';
import { isObject } from './isObject';
import type { DeepRequired, NonNullObject } from './types';
import type { DeepRequired } from './types';

/**
* Deep merges 2 objects. Properties from the second parameter are applied to the first.
Expand Down Expand Up @@ -40,7 +40,7 @@ import type { DeepRequired, NonNullObject } from './types';
* mergeDefault(base, overwrites) // { a: { b: 5 } };
* ```
*/
export function mergeDefault<A extends NonNullObject, B extends Partial<A>>(base: A, overwrites?: B): DeepRequired<A & B> {
export function mergeDefault<A extends object, B extends Partial<A>>(base: A, overwrites?: B): DeepRequired<A & B> {
// If no overwrites are specified then deep clone the base
if (!overwrites) return deepClone(base) as DeepRequired<A & B>;

Expand All @@ -50,7 +50,7 @@ export function mergeDefault<A extends NonNullObject, B extends Partial<A>>(base
if (typeof overwritesValueAtBaseKey === 'undefined') {
Reflect.set(overwrites, baseKey, deepClone(baseValue));
} else if (isObject(overwritesValueAtBaseKey)) {
Reflect.set(overwrites, baseKey, mergeDefault((baseValue ?? {}) as NonNullObject, overwritesValueAtBaseKey));
Reflect.set(overwrites, baseKey, mergeDefault((baseValue ?? {}) as object, overwritesValueAtBaseKey));
}
}

Expand Down
4 changes: 1 addition & 3 deletions packages/utilities/src/lib/objectEntries.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { NonNullObject } from './types';

export function objectEntries<T extends NonNullObject>(obj: T): T extends ArrayLike<any> ? [`${number}`, T[number]][] : [keyof T, T[keyof T]][] {
export function objectEntries<T extends object>(obj: T): T extends ArrayLike<any> ? [`${number}`, T[number]][] : [keyof T, T[keyof T]][] {
return Object.entries(obj) as T extends ArrayLike<infer Values> ? Values[] : [keyof T, T[keyof T]][];
}
4 changes: 1 addition & 3 deletions packages/utilities/src/lib/objectKeys.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { NonNullObject } from './types';

export function objectKeys<T extends NonNullObject>(obj: T): T extends ArrayLike<any> ? `${number}`[] : (keyof T)[] {
export function objectKeys<T extends object>(obj: T): T extends ArrayLike<any> ? `${number}`[] : (keyof T)[] {
return Object.keys(obj) as T extends ArrayLike<infer Values> ? Values[] : (keyof T)[];
}
3 changes: 1 addition & 2 deletions packages/utilities/src/lib/objectToTuples.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { isObject } from './isObject';
import type { AnyObject } from './types';

/**
* Convert an object to a tuple
* @param obj The object to convert
* @param prefix The prefix for the key
*/
export function objectToTuples<T>(obj: AnyObject<T>, prefix = ''): [keyof T, T[keyof T]][] {
export function objectToTuples<T extends object>(obj: T, prefix = ''): [keyof T, T[keyof T]][] {
const entries: [keyof T, T[keyof T]][] = [];

for (const [key, value] of Object.entries(obj)) {
Expand Down
4 changes: 1 addition & 3 deletions packages/utilities/src/lib/objectValues.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { NonNullObject } from './types';

export function objectValues<T extends NonNullObject>(obj: T): T extends ArrayLike<any> ? T[number][] : T[keyof T][] {
export function objectValues<T extends object>(obj: T): T extends ArrayLike<any> ? T[number][] : T[keyof T][] {
return Object.values(obj) as T extends ArrayLike<infer Values> ? Values[] : T[keyof T][];
}
6 changes: 5 additions & 1 deletion packages/utilities/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ export type NonNullableProperties<T = unknown> = {

/**
* An object that is non nullable, to bypass TypeScript not easily working with `Record<PropertyKey, unknown>` in various instances.
*
* @deprecated Use the `object` type instead.
*/
// eslint-disable-next-line @typescript-eslint/ban-types
export type NonNullObject = {} & object;
Expand All @@ -122,6 +124,8 @@ export type NonNullObject = {} & object;
* that leads to unexpected type resolutions.
*
* Note that this is still a strictly typed type, it is not simply aliasing `any`
*
* @deprecated Use the `object` type instead.
*/
export type AnyObject<T> = {
[K in keyof T]: T[K];
Expand Down Expand Up @@ -167,7 +171,7 @@ export type PickByValue<T, V> = {
* ```
*/
export type Mutable<T> = {
-readonly [P in keyof T]: T[P] extends Array<unknown> | NonNullObject ? Mutable<T[P]> : T[P];
-readonly [P in keyof T]: T[P] extends Array<unknown> | object ? Mutable<T[P]> : T[P];
};

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/utilities/tests/getDeepObjectKeys.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDeepObjectKeys, type GetDeepObjectKeysOptions, type NonNullObject } from '../src';
import { getDeepObjectKeys, type GetDeepObjectKeysOptions } from '../src';

describe('getDeepObjectKeys', () => {
const scenarios: Scenario[] = [
Expand All @@ -19,4 +19,4 @@ describe('getDeepObjectKeys', () => {
});
});

type Scenario = [NonNullObject, GetDeepObjectKeysOptions, string[]];
type Scenario = [object, GetDeepObjectKeysOptions, string[]];