export function exactlyOne( input: ReadonlyArray, property: string, extraDescription: string = '' ): T { if (input.length !== 1) { throw new Error( `Expected exactly one ${property} element, got ${input.length}. ${extraDescription}` ); } return input[0]; } export function optionalOne( input: ReadonlyArray, property: string, extraDescription: string = '' ): T | undefined { if (input.length > 1) { throw new Error( `Expected one optional ${property} element, got ${input.length}. ${extraDescription}` ); } return input[0]; } export function required( input: T | undefined, property: string, extraDescription: string = '' ): NonNullable { if (input == null) { throw new Error( `Expected a value for ${property}, got undefined. ${extraDescription}` ); } return input; } export function allRequired( input: ReadonlyArray, property: string, extraDescription: string = '' ): Array> { return input.map((v, i) => required(v, `${property}[${i}]`, extraDescription) ); } export function atLeastOne( input: ReadonlyArray, property: string, extraDescription: string = '' ): ReadonlyArray { if (input.length === 0) { throw new Error( `Expected at least one ${property} element. ${extraDescription}` ); } return input; } export function atLeastOneAndAllRequired( input: ReadonlyArray, property: string, extraDescription: string = '' ): ReadonlyArray> { return atLeastOne( allRequired(input, property, extraDescription), property, extraDescription ); } export function valueForKey( input: Record, key: string, extraDescription: string = '' ): T { return required(input[key], key, extraDescription); } export function valuesForKeys( input: Record, keys: string[], extraDescription: string = '' ): T[] { return keys.map((key) => valueForKey(input, key, extraDescription)); }