Skip to content

Commit

Permalink
Add SingleKeyObject and IfEmptyObject types (#849)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
ash-zzz and sindresorhus committed Mar 31, 2024
1 parent 2ab1c51 commit fa1c3f3
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 1 deletion.
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type {KeysOfUnion} from './source/keys-of-union';
export type {DistributedOmit} from './source/distributed-omit';
export type {DistributedPick} from './source/distributed-pick';
export type {EmptyObject, IsEmptyObject} from './source/empty-object';
export type {IfEmptyObject} from './source/if-empty-object';
export type {NonEmptyObject} from './source/non-empty-object';
export type {UnknownRecord} from './source/unknown-record';
export type {UnknownArray} from './source/unknown-array';
Expand All @@ -23,6 +24,7 @@ export type {RequireAtLeastOne} from './source/require-at-least-one';
export type {RequireExactlyOne} from './source/require-exactly-one';
export type {RequireAllOrNone} from './source/require-all-or-none';
export type {RequireOneOrNone} from './source/require-one-or-none';
export type {SingleKeyObject} from './source/single-key-object';
export type {OmitIndexSignature} from './source/omit-index-signature';
export type {PickIndexSignature} from './source/pick-index-signature';
export type {PartialDeep, PartialDeepOptions} from './source/partial-deep';
Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ Click the type names for complete docs.
### Utilities

- [`EmptyObject`](source/empty-object.d.ts) - Represents a strictly empty plain object, the `{}` value.
- [`IsEmptyObject`](source/empty-object.d.ts) - Returns a `boolean` for whether the type is strictly equal to an empty plain object, the `{}` value.
- [`NonEmptyObject`](source/non-empty-object.d.ts) - Represents an object with at least 1 non-optional key.
- [`UnknownRecord`](source/unknown-record.d.ts) - Represents an object with `unknown` value. You probably want this instead of `{}`.
- [`UnknownArray`](source/unknown-array.d.ts) - Represents an array with `unknown` value.
Expand All @@ -125,6 +124,7 @@ Click the type names for complete docs.
- [`RequireExactlyOne`](source/require-exactly-one.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more.
- [`RequireAllOrNone`](source/require-all-or-none.d.ts) - Create a type that requires all of the given keys or none of the given keys.
- [`RequireOneOrNone`](source/require-one-or-none.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more, or none of the given keys.
- [`SingleKeyObject`](source/single-key-object.d.ts) - Create a type that only accepts an object with a single key.
- [`RequiredDeep`](source/required-deep.d.ts) - Create a deeply required version of another type. Use [`Required<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) if you only need one level deep.
- [`PickDeep`](source/pick-deep.d.ts) - Pick properties from a deeply-nested object. Use [`Pick<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys) if you only need one level deep.
- [`OmitDeep`](source/omit-deep.d.ts) - Omit properties from a deeply-nested object. Use [`Omit<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) if you only need one level deep.
Expand Down Expand Up @@ -220,6 +220,7 @@ type ShouldBeNever = IfAny<'not any', 'not never', 'never'>;
- [`IsAny`](source/is-any.d.ts) - Returns a boolean for whether the given type is `any`. (Conditional version: [`IfAny`](source/if-any.d.ts).)
- [`IsNever`](source/is-never.d.ts) - Returns a boolean for whether the given type is `never`. (Conditional version: [`IfNever`](source/if-never.d.ts).)
- [`IsUnknown`](source/is-unknown.d.ts) - Returns a boolean for whether the given type is `unknown`. (Conditional version: [`IfUnknown`](source/if-unknown.d.ts).)
- [`IsEmptyObject`](source/empty-object.d.ts) - Returns a boolean for whether the type is strictly equal to an empty plain object, the `{}` value. (Conditional version: [`IfEmptyObject`](source/if-empty-object.d.ts))

### JSON

Expand Down
26 changes: 26 additions & 0 deletions source/if-empty-object.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type {IsEmptyObject} from './empty-object';

/**
An if-else-like type that resolves depending on whether the given type is `{}`.
@see {@link IsEmptyObject}
@example
```
import type {IfEmptyObject} from 'type-fest';
type ShouldBeTrue = IfEmptyObject<{}>;
//=> true
type ShouldBeBar = IfEmptyObject<{key: any}, 'foo', 'bar'>;
//=> 'bar'
```
@category Type Guard
@category Utilities
*/
export type IfEmptyObject<
T,
TypeIfEmptyObject = true,
TypeIfNotEmptyObject = false,
> = IsEmptyObject<T> extends true ? TypeIfEmptyObject : TypeIfNotEmptyObject;
29 changes: 29 additions & 0 deletions source/single-key-object.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type {IfEmptyObject} from '../index';
import type {IsUnion} from './internal';

/**
Create a type that only accepts an object with a single key.
@example
```
import type {SingleKeyObject} from 'type-fest';
const someFunction = <T>(parameter: SingleKeyObject<T>) => {};
someFunction({
value: true
});
someFunction({
value: true,
otherKey: true
});
// Error: Argument of type '{value: boolean; otherKey: boolean}' is not assignable to parameter of type 'never'.ts(2345)
```
@category Object
*/
export type SingleKeyObject<ObjectType> =
IsUnion<keyof ObjectType> extends true
? never
: IfEmptyObject<ObjectType, never, ObjectType>;
15 changes: 15 additions & 0 deletions test-d/single-key-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {expectNever, expectError, expectAssignable} from 'tsd';
import type {SingleKeyObject} from '../index';

const test = <T>(_: SingleKeyObject<T>): void => {}; // eslint-disable-line @typescript-eslint/no-empty-function

test({key: 'value'});

expectError(test({}));
expectError(test({key: 'value', otherKey: 'other value'}));

declare const validObject: SingleKeyObject<{key: string}>;
expectAssignable<{key: string}>(validObject);

declare const invalidObject: SingleKeyObject<{key1: string; key2: number}>;
expectNever(invalidObject);

0 comments on commit fa1c3f3

Please sign in to comment.