import type { Entries } from 'type-fest' export type UnknownRecord = Record /** * See https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208 for * some background on why this exists and why this isn't in TypeScript by default. */ export function isRecord(value: unknown): value is UnknownRecord { return typeof value === 'object' && value !== null && !Array.isArray(value) } export function isObjectLike(value: unknown): value is UnknownRecord { return (typeof value === 'object' && value !== null) || typeof value === 'function' } export function isPlainRecord(value: unknown): value is UnknownRecord { return isRecord(value) } export function isStringRecord(value: unknown): value is Record { if (!isRecord(value)) { return false } return Object.values(value).every((entry) => typeof entry === 'string') } export function getRecordProperty(value: unknown, property: PropertyKey): unknown { if (!isRecord(value)) { return undefined } return value[property] } export function getNestedRecordProperty( value: unknown, first: PropertyKey, second: PropertyKey, ): unknown { return getRecordProperty(getRecordProperty(value, first), second) } export function getStringProperty(value: unknown, property: PropertyKey): string | undefined { const propertyValue = getRecordProperty(value, property) return typeof propertyValue === 'string' ? propertyValue : undefined } export function getNestedStringProperty( value: unknown, first: PropertyKey, second: PropertyKey, ): string | undefined { const propertyValue = getNestedRecordProperty(value, first, second) return typeof propertyValue === 'string' ? propertyValue : undefined } export function getNumberProperty(value: unknown, property: PropertyKey): number | undefined { const propertyValue = getRecordProperty(value, property) return typeof propertyValue === 'number' ? propertyValue : undefined } export function getNestedNumberProperty( value: unknown, first: PropertyKey, second: PropertyKey, ): number | undefined { const propertyValue = getNestedRecordProperty(value, first, second) return typeof propertyValue === 'number' ? propertyValue : undefined } /** * Returns properly typed entries of an object */ export function entries(object: T): Entries { return Object.entries(object) as Entries } /** * Returns properly typed values of an object */ export function values(object: T): T[keyof T][] { return Object.values(object) } /** * Returns properly typed keys of an object */ export function keys(object: T): (keyof T)[] { return Object.keys(object) as (keyof T)[] }