UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

1 lines 9.26 kB
{"version":3,"file":"pickBy.cjs","names":["purry","out: Partial<Record<string, unknown>>"],"sources":["../src/pickBy.ts"],"sourcesContent":["import type { IsNever, Simplify } from \"type-fest\";\nimport type { EnumerableStringKeyOf } from \"./internal/types/EnumerableStringKeyOf\";\nimport type { EnumerableStringKeyedValueOf } from \"./internal/types/EnumerableStringKeyedValueOf\";\nimport type { IsBoundedRecord } from \"./internal/types/IsBoundedRecord\";\nimport type { ToString } from \"./internal/types/ToString\";\nimport { purry } from \"./purry\";\n\n// When the predicate isn't a type-guard we don't know which properties would be\n// part of the output and which wouldn't so we can only safely downgrade the\n// whole object to a Partial of the input.\ntype EnumeratedPartial<T> = T extends unknown\n ? Simplify<\n IsBoundedRecord<T> extends true\n ? {\n // Object.entries returns keys as strings.\n -readonly [P in keyof T as ToString<P>]?: Required<T>[P];\n }\n : // For unbounded records (a simple Record with primitive `string` or\n // `number` keys) the return type here could technically be T; but for\n // cases where the record is unbounded but is more complex (like\n // `symbol` keys) we want to \"reconstruct\" the record from just its\n // enumerable components (which are the ones accessible via\n // `Object.entries`).\n Record<EnumerableStringKeyOf<T>, EnumerableStringKeyedValueOf<T>>\n >\n : never;\n\n// When the predicate is a type-guard we have more information to work with when\n// constructing the type of the output object. We can safely remove any property\n// which value would never come up true for the predicate, AND we can also\n// assume that properties that match the predicate perfectly would **always**\n// show up in the output object. Hence to build the output object we need to\n// build and merge 2 output objects: One for the properties which have a value\n// of at type that would always yield a `true` result from the predicate, these\n// are the \"matches\", which would not change the \"optionality\" of the input\n// object's props, and one for partial matches which would also make the props\n// optional (as they could have a value that would be filtered out).\ntype EnumeratedPartialNarrowed<T, S> = T extends unknown\n ? Simplify<\n IsBoundedRecord<T> extends true\n ? ExactProps<T, S> & PartialProps<T, S>\n : // For unbounded records we need to \"reconstruct\" the record and\n // narrow the value types. Similar to the non-narrowed case, we need\n // to also ignore `symbol` keys and any values that are only relevant\n // to them.\n Record<\n EnumerableStringKeyOf<T>,\n Extract<EnumerableStringKeyedValueOf<T>, S>\n >\n >\n : never;\n\n// The exact case, props here would always be part of the output object\ntype ExactProps<T, S> = {\n // Object.entries returns keys as strings.\n -readonly [P in keyof T as ToString<\n IsExactProp<T, P, S> extends true ? P : never\n >]: Extract<Required<T>[P], S>;\n};\n\n// The partial case, props here might be part of the output object, but might\n// not be, hence they are optional.\ntype PartialProps<T, S> = {\n // Object.entries returns keys as strings.\n -readonly [P in keyof T as ToString<\n IsPartialProp<T, P, S> extends true ? P : never\n >]?: IsNever<Extract<T[P], S>> extends true\n ? // If the result of extracting S from T[P] is never but S still extends\n // it, it means that T[P] is too wide and S can't be extracted from it:\n // e.g. if T[P] is `number` S is `1` then `Extract<number, 1> === never`.\n // For these cases we can return S directly as the type as it's already\n // very narrowed compared to T[P].\n S extends T[P]\n ? S\n : never\n : Extract<T[P], S>;\n};\n\n// If the input object's value type extends itself when the type-guard is\n// extracted from it we can safely assume that the predicate would always return\n// true for any value of that property.\ntype IsExactProp<T, P extends keyof T, S> =\n T[P] extends Extract<T[P], S> ? true : false;\n\n// ...and if the input object's value type isn't an exact match, but still has\n// some partial match (i.g. the extracted type-guard isn't completely disjoint)\n// then we can assume that the property can sometimes return true, and sometimes\n// false when passed to the predicate, hence it should be optional in the\n// output.\ntype IsPartialProp<T, P extends keyof T, S> =\n IsExactProp<T, P, S> extends true\n ? false\n : IsNever<Extract<T[P], S>> extends true\n ? S extends T[P]\n ? // If the result of extracting S from T[P] is never but S still\n // extends it, it means that T[P] is too wide and S can't be\n // extracted from it: e.g. if T[P] is `number` S is `1` then\n // `Extract<number, 1> === never`, but `1` extends `number`. We need\n // to handle these cases when we extract the value too (see above).\n true\n : false\n : true;\n\n/**\n * Iterates over the entries of `data` and reconstructs the object using only\n * entries that `predicate` accepts. Symbol keys are not passed to the predicate\n * and would be filtered out from the output object.\n *\n * See `omitBy` for a complementary function which starts with a shallow copy of\n * the input object and removes the entries that the predicate rejects. Because\n * it is subtractive symbol keys would be copied over to the output object.\n * See also `entries`, `filter`, and `fromEntries` which could be used to build\n * your own version of `pickBy` if you need more control (though the resulting\n * type might be less precise).\n *\n * @param data - The target object.\n * @param predicate - A function that takes the value, key, and the data itself\n * and returns true if the entry should be part of the output object, or `false`\n * to remove it. If the function is a type-guard on the value the output type\n * would be narrowed accordingly.\n * @returns A shallow copy of the input object with the rejected entries\n * removed.\n * @signature R.pickBy(data, predicate)\n * @example\n * R.pickBy({a: 1, b: 2, A: 3, B: 4}, (val, key) => key.toUpperCase() === key) // => {A: 3, B: 4}\n * @dataFirst\n * @category Object\n */\nexport function pickBy<\n T extends object,\n S extends EnumerableStringKeyedValueOf<T>,\n>(\n data: T,\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => value is S,\n): EnumeratedPartialNarrowed<T, S>;\nexport function pickBy<T extends object>(\n data: T,\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => boolean,\n): EnumeratedPartial<T>;\n\n/**\n * Iterates over the entries of `data` and reconstructs the object using only\n * entries that `predicate` accepts. Symbol keys are not passed to the predicate\n * and would be filtered out from the output object.\n *\n * See `omitBy` for a complementary function which starts with a shallow copy of\n * the input object and removes the entries that the predicate rejects. Because\n * it is subtractive symbol keys would be copied over to the output object.\n * See also `entries`, `filter`, and `fromEntries` which could be used to build\n * your own version of `pickBy` if you need more control (though the resulting\n * type might be less precise).\n *\n * @param predicate - A function that takes the value, key, and the data itself\n * and returns true if the entry should be part of the output object, or `false`\n * to remove it. If the function is a type-guard on the value the output type\n * would be narrowed accordingly.\n * @signature\n * R.pickBy(predicate)(data)\n * @example\n * R.pipe({a: 1, b: 2, A: 3, B: 4}, pickBy((val, key) => key.toUpperCase() === key)); // => {A: 3, B: 4}\n * @dataLast\n * @category Object\n */\nexport function pickBy<\n T extends object,\n S extends EnumerableStringKeyedValueOf<T>,\n>(\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => value is S,\n): (data: T) => EnumeratedPartialNarrowed<T, S>;\nexport function pickBy<T extends object>(\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => boolean,\n): (data: T) => EnumeratedPartial<T>;\n\nexport function pickBy(...args: ReadonlyArray<unknown>): unknown {\n return purry(pickByImplementation, args);\n}\n\nfunction pickByImplementation<T extends object>(\n data: T,\n predicate: (value: unknown, key: string, data: T) => boolean,\n): Record<string, unknown> {\n const out: Partial<Record<string, unknown>> = {};\n\n for (const [key, value] of Object.entries(data)) {\n if (predicate(value, key, data)) {\n out[key] = value;\n }\n }\n\n return out;\n}\n"],"mappings":"wCA6LA,SAAgB,EAAO,GAAG,EAAuC,CAC/D,OAAOA,EAAAA,EAAM,EAAsB,EAAK,CAG1C,SAAS,EACP,EACA,EACyB,CACzB,IAAMC,EAAwC,EAAE,CAEhD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAK,CACzC,EAAU,EAAO,EAAK,EAAK,GAC7B,EAAI,GAAO,GAIf,OAAO"}