Created
December 2, 2024 00:08
-
-
Save wolever/c921b5c1c05387925acd029cc9427ece to your computer and use it in GitHub Desktop.
Type-safe definitions of `Object.keys`, `Object.entries`, and `Object.values`: `objectKeys`, `objectEntries`, and `objectValues`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ObjectType matches any "regular" object. | |
* | |
* For example: | |
* > {} satisfies ObjectType | |
* > { a: 1, b: 2 } satisfies ObjectType | |
* > [] satisfies ObjectType | |
* > null satisfies ObjectType | |
* TypeError: 'null' does not satisfy 'ObjectType'. | |
* > undefined satisfies ObjectType | |
* TypeError: 'undefined' does not satisfy 'ObjectType'. | |
* > 1 satisfies ObjectType | |
* TypeError: 'number' does not satisfy 'ObjectType'. | |
* > 'string' satisfies ObjectType | |
* TypeError: 'string' does not satisfy 'ObjectType'. | |
* > true satisfies ObjectType | |
* TypeError: 'boolean' does not satisfy 'ObjectType'. | |
*/ | |
export type ObjectType = Record<PropertyKey, any>; | |
// Source: https://github.com/sindresorhus/ts-extras/blob/main/source/object-keys.ts | |
type ObjectKeys<T> = `${Exclude<keyof T, symbol>}`; | |
// Source: https://dev.to/harry0000/a-bit-convenient-typescript-type-definitions-for-objectentries-d6g | |
type TupleEntry<T extends readonly unknown[], I extends unknown[] = [], R = never> = T extends | |
readonly [infer Head, ...infer Tail] ? TupleEntry<Tail, [...I, unknown], R | [`${I['length']}`, Head]> | |
: R; | |
type ObjectEntry<T> = T extends object | |
? { [K in keyof T]: [K, Required<T>[K]] }[keyof T] extends infer E | |
? E extends [infer K, infer V] ? K extends string | number ? [`${K}`, V] | |
: never | |
: never | |
: never | |
: never; | |
type Entry<T> = T extends readonly [unknown, ...unknown[]] ? TupleEntry<T> | |
: T extends ReadonlyArray<infer U> ? [`${number}`, U] | |
: ObjectEntry<T>; | |
/** | |
* A strongly-typed version of `Object.keys()`. | |
*/ | |
export const objectKeys = Object.keys as <T extends ObjectType>(value: T) => Array<ObjectKeys<T>>; | |
/** | |
* A strongly-typed version of `Object.entries()`. | |
*/ | |
export const objectEntries = Object.entries as <T extends ObjectType>(value: T) => ReadonlyArray<Entry<T>>; | |
/** | |
* A strongly-typed version of `Object.values()`. | |
*/ | |
export const objectValues = Object.values as <T extends ObjectType, K extends keyof T>(value: T) => ReadonlyArray<T[K]>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment