import type {KeysOfUnion} from './internal'; /** Extract the element of an array that also works for array union. Returns `never` if T is not an array. It creates a type-safe way to access the element type of `unknown` type. */ type ArrayElement = T extends readonly unknown[] ? T[0] : never; /** Extract the object field type if T is an object and K is a key of T, return `never` otherwise. It creates a type-safe way to access the member type of `unknown` type. */ type ObjectValue = K extends keyof T ? T[K] : never; /** Create a type from `ParameterType` and `InputType` and change keys exclusive to `InputType` to `never`. - Generate a list of keys that exists in `InputType` but not in `ParameterType`. - Mark these excess keys as `never`. */ type ExactObject = {[Key in keyof ParameterType]: Exact>} & Record>, never>; /** Create a type that does not allow extra properties, meaning it only allows properties that are explicitly declared. This is useful for function type-guarding to reject arguments with excess properties. Due to the nature of TypeScript, it does not complain if excess properties are provided unless the provided value is an object literal. *Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/12936) if you want to have this type as a built-in in TypeScript.* @example ``` type OnlyAcceptName = {name: string}; function onlyAcceptName(args: OnlyAcceptName) {} // TypeScript complains about excess properties when an object literal is provided. onlyAcceptName({name: 'name', id: 1}); //=> `id` is excess // TypeScript does not complain about excess properties when the provided value is a variable (not an object literal). const invalidInput = {name: 'name', id: 1}; onlyAcceptName(invalidInput); // No errors ``` Having `Exact` allows TypeScript to reject excess properties. @example ``` import {Exact} from 'type-fest'; type OnlyAcceptName = {name: string}; function onlyAcceptNameImproved>(args: T) {} const invalidInput = {name: 'name', id: 1}; onlyAcceptNameImproved(invalidInput); // Compilation error ``` [Read more](https://stackoverflow.com/questions/49580725/is-it-possible-to-restrict-typescript-object-to-contain-only-properties-defined) @category Utilities */ export type Exact = // Convert union of array to array of union: A[] & B[] => (A & B)[] ParameterType extends unknown[] ? Array, ArrayElement>> // In TypeScript, Array is a subtype of ReadonlyArray, so always test Array before ReadonlyArray. : ParameterType extends readonly unknown[] ? ReadonlyArray, ArrayElement>> : ParameterType extends object ? ExactObject : ParameterType;