diff --git a/index.d.ts b/index.d.ts index 9a05a87d..85140b9d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -6,6 +6,7 @@ export * from './source/observable-like'; // Utilities export type {EmptyObject, IsEmptyObject} from './source/empty-object'; +export type {UnknownRecord} from './source/unknown-record'; export type {Except} from './source/except'; export type {TaggedUnion} from './source/tagged-union'; export type {Writable} from './source/writable'; diff --git a/readme.md b/readme.md index 1296c343..aba78a37 100644 --- a/readme.md +++ b/readme.md @@ -110,6 +110,7 @@ Click the type names for complete docs. - [`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. +- [`UnknownRecord`](source/unknown-record.d.ts) - Represents an object with `unknown` value. You probably want this instead of `{}`. - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys). - [`Writable`](source/writable.d.ts) - Create a type that strips `readonly` from all or some of an object's keys. The inverse of `Readonly`. - [`WritableDeep`](source/writable-deep.d.ts) - Create a deeply mutable version of an `object`/`ReadonlyMap`/`ReadonlySet`/`ReadonlyArray` type. The inverse of `ReadonlyDeep`. Use `Writable` if you only need one level deep. diff --git a/source/internal.d.ts b/source/internal.d.ts index bb369115..ea479aaa 100644 --- a/source/internal.d.ts +++ b/source/internal.d.ts @@ -3,6 +3,9 @@ import type {Simplify} from './simplify'; import type {Trim} from './trim'; import type {IsAny} from './is-any'; +// TODO: Remove for v5. +export type {UnknownRecord} from './unknown-record'; + /** Infer the length of the given array ``. @@ -77,11 +80,6 @@ export type Whitespace = export type WordSeparators = '-' | '_' | Whitespace; -/** -Matches any unknown record. -*/ -export type UnknownRecord = Record; - /** Matches any unknown array or tuple. */ diff --git a/source/merge-deep.d.ts b/source/merge-deep.d.ts index 19e2684e..3fcaab2e 100644 --- a/source/merge-deep.d.ts +++ b/source/merge-deep.d.ts @@ -9,8 +9,8 @@ import type { IsBothExtends, NonEmptyTuple, UnknownArrayOrTuple, - UnknownRecord, } from './internal'; +import type {UnknownRecord} from './unknown-record'; /** Deeply simplifies an object excluding iterables and functions. Used internally to improve the UX and accept both interfaces and type aliases as inputs. diff --git a/source/unknown-record.d.ts b/source/unknown-record.d.ts new file mode 100644 index 00000000..270fc5b1 --- /dev/null +++ b/source/unknown-record.d.ts @@ -0,0 +1,31 @@ +/** +Represents an object with `unknown` value. You probably want this instead of `{}`. + +Use case: You have an object whose keys and values are unknown to you. + +@example +``` +import type {UnknownRecord} from 'type-fest'; + +function toJson(object: UnknownRecord) { + return JSON.stringify(object); +} + +toJson({hello: 'world'}); +//=> '{"hello":"world"}' + +function isObject(value: unknown): value is UnknownRecord { + return typeof value === 'object' && value !== null; +} + +isObject({hello: 'world'}); +//=> true + +isObject('hello'); +//=> false +``` + +@category Type +@category Object +*/ +export type UnknownRecord = Record; diff --git a/test-d/unknown-record.ts b/test-d/unknown-record.ts new file mode 100644 index 00000000..89b9caf4 --- /dev/null +++ b/test-d/unknown-record.ts @@ -0,0 +1,17 @@ +import {expectAssignable, expectError, expectType} from 'tsd'; +import type {UnknownRecord} from '../index'; + +declare let foo: UnknownRecord; + +expectAssignable(foo); +expectAssignable(foo = {}); +expectAssignable(foo = {bar: 'baz'}); +expectAssignable(foo = {bar: {baz: 'hello'}}); + +expectError(foo = []); +expectError(foo = 42); +expectError(foo = null); + +expectType(foo.bar); +// eslint-disable-next-line @typescript-eslint/dot-notation +expectType(foo['bar']);