import { PlainObject, Predicate, Static } from '../types' import { isObject } from '../predicates/isObject' export const shape = ( shape: T, ): Predicate> => { const predicates = Object.keys(shape).map((key) => { const valuePredicate = shape[key] return (object: PlainObject): object is any => valuePredicate(object[key]) }) return ( value: unknown, ): value is StaticShape => { let isValid = isObject(value) if (isValid) { for (let i = 0; i < predicates.length; ++i) { isValid = predicates[i](value as PlainObject) if (!isValid) { break } } } return isValid } } type ShapePredicateRecord = Record> type StaticShape = { [P in { [K in keyof T]: Extract, undefined> extends never ? K : never }[keyof T]]: Static } & { [P in { [K in keyof T]: Extract, undefined> extends never ? never : K }[keyof T]]?: Static }