UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

1 lines 7.76 kB
{"version":3,"file":"omitBy.cjs","names":["purry","out: Partial<Record<string, unknown>>"],"sources":["../src/omitBy.ts"],"sourcesContent":["import type { IsNever, Or, 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 { purry } from \"./purry\";\n\n// Symbols are not passed to the predicate (because they can't be enumerated\n// with the `Object.entries` function) and the output object is built from a\n// shallow copy of the input; meaning symbols would just be passed through as-\n// is.\ntype PickSymbolKeys<T extends object> = {\n -readonly [P in keyof T as P extends symbol ? P : never]: T[P];\n};\n\n// When we don't use a type-predicate we can't say anything about what props\n// would be omitted from the output, so we need to assume any of them could be\n// filtered out. This means that we effectively make all (enumerable) keys\n// optional.\ntype PartialEnumerableKeys<T extends object> =\n // `extends unknown` is always going to be the case and is used to convert any\n // union into a [distributive conditional type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).\n T extends unknown\n ? Simplify<\n IsBoundedRecord<T> extends true\n ? PickSymbolKeys<T> & {\n -readonly [P in keyof T as P extends symbol\n ? never\n : P]?: Required<T>[P];\n }\n : // This is the type you'd get from doing:\n // `Object.fromEntries(Object.entries(x))`.\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 always be true for the predicate, AND we can also\n// assume that properties that are rejected by the predicate perfectly would\n// **always** show up in the output object. Hence to build the output object we\n// need to build and merge 2 output objects: One for the properties which have a\n// value of at type that would always yield a `false` result from the predicate,\n// these are the \"matches\", which would not change the \"optionality\" of the\n// input object's props, and one for partial matches which would also make the\n// props optional (as they could have a value that would be filtered out).\ntype PartialEnumerableKeysNarrowed<T extends object, S> = Simplify<\n ExactProps<T, S> & PartialProps<T, S> & PickSymbolKeys<T>\n>;\n\n// The exact case, props here would always be part of the output object\ntype ExactProps<T, S> = {\n -readonly [P in keyof T as IsExactProp<T, P, S> extends true\n ? P\n : never]: Exclude<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 -readonly [P in keyof T as IsPartialProp<T, P, S> extends true\n ? P\n : never]?: Exclude<T[P], S>;\n};\n\n// If the input object's value type extends itself when the type-guard is\n// excluded from it we can safely assume that the predicate would always return\n// `false` for any value of that property.\ntype IsExactProp<T, P extends keyof T, S> = P extends symbol\n ? // Symbols are passed through via the PickSymbolKeys type\n false\n : T[P] extends Exclude<T[P], S>\n ? S extends T[P]\n ? // If S extends the T[P] it means the type the predicate is narrowing to\n // can't narrow the rejected value any further, so we can't say what\n // would happen for a concrete value in runtime (e.g. if T[P] is\n // `number` and S is `1`: `Exclude<number, 1> === number`.\n false\n : true\n : 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> = P extends symbol\n ? // Symbols are passed through via the PickSymbolKeys type\n false\n : Or<IsExactProp<T, P, S>, IsNever<Exclude<Required<T>[P], S>>> extends true\n ? false\n : true;\n\n/**\n * Creates a shallow copy of the data, and then removes any keys that the\n * predicate rejects. Symbol keys are not passed to the predicate and would be\n * passed through to the output as-is.\n *\n * See `pickBy` for a complementary function which starts with an empty object\n * and adds the entries that the predicate accepts. Because it is additive,\n * symbol keys will not be passed through to the output object.\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 shouldn't be part of the output object, or\n * `false` to keep it. If the function is a type-guard on the value the output\n * type would be narrowed accordingly.\n * @returns A shallow copy of the input object with the rejected entries\n * removed.\n * @signature R.omitBy(data, predicate)\n * @example\n * R.omitBy({a: 1, b: 2, A: 3, B: 4}, (val, key) => key.toUpperCase() === key) // => {a: 1, b: 2}\n * @dataFirst\n * @category Object\n */\nexport function omitBy<\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): PartialEnumerableKeysNarrowed<T, S>;\nexport function omitBy<T extends object>(\n data: T,\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => boolean,\n): PartialEnumerableKeys<T>;\n\n/**\n * Returns a partial copy of an object omitting the keys matching predicate.\n *\n * @param predicate - The predicate.\n * @signature R.omitBy(fn)(object)\n * @example\n * R.omitBy((val, key) => key.toUpperCase() === key)({a: 1, b: 2, A: 3, B: 4}) // => {a: 1, b: 2}\n * @dataLast\n * @category Object\n */\nexport function omitBy<\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) => PartialEnumerableKeysNarrowed<T, S>;\nexport function omitBy<T extends object>(\n predicate: (\n value: EnumerableStringKeyedValueOf<T>,\n key: EnumerableStringKeyOf<T>,\n data: T,\n ) => boolean,\n): (data: T) => PartialEnumerableKeys<T>;\n\nexport function omitBy(...args: ReadonlyArray<unknown>): unknown {\n return purry(omitByImplementation, args);\n}\n\nfunction omitByImplementation<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>> = { ...data };\n\n for (const [key, value] of Object.entries(out)) {\n if (predicate(value, key, data)) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete -- This is the best way to do it!\n delete out[key];\n }\n }\n\n return out;\n}\n"],"mappings":"wCAkKA,SAAgB,EAAO,GAAG,EAAuC,CAC/D,OAAOA,EAAAA,EAAM,EAAsB,EAAK,CAG1C,SAAS,EACP,EACA,EACyB,CACzB,IAAMC,EAAwC,CAAE,GAAG,EAAM,CAEzD,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,EAAI,CACxC,EAAU,EAAO,EAAK,EAAK,EAE7B,OAAO,EAAI,GAIf,OAAO"}