Skip to content

Commit de74eb8

Browse files
authoredMar 1, 2024··
Struct: make pick / omit dual (#2233)
1 parent 465be79 commit de74eb8

File tree

4 files changed

+56
-21
lines changed

4 files changed

+56
-21
lines changed
 

‎.changeset/silly-lobsters-admire.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Struct: make `pick` / `omit` dual

‎packages/effect/dtslint/Struct.ts

+9
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ pipe(hole<Record<string, number> & { a: boolean }>(), S.pick("b"))
149149
// $ExpectType { a?: string; b: number; }
150150
pipe(optionalStringStruct, S.pick("a", "b"))
151151

152+
// $ExpectType { a: string; b: number; }
153+
S.pick(stringStruct, "a", "b")
154+
155+
// $ExpectType { a?: number; b?: number; }
156+
S.pick(stringNumberRecord, "a", "b")
157+
152158
// -------------------------------------------------------------------------------------
153159
// omit
154160
// -------------------------------------------------------------------------------------
@@ -191,3 +197,6 @@ pipe(numberNumberRecord, S.omit(1))
191197

192198
// $ExpectType { a?: string; b: number; }
193199
pipe(optionalStringStruct, S.omit("c"))
200+
201+
// $ExpectType { b: number; c: boolean; }
202+
S.omit(stringStruct, "a")

‎packages/effect/src/Struct.ts

+40-21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import * as Equivalence from "./Equivalence.js"
88
import { dual } from "./Function.js"
99
import * as order from "./Order.js"
10+
import * as Predicate from "./Predicate.js"
1011
import type { MatchRecord, Simplify } from "./Types.js"
1112

1213
/**
@@ -17,23 +18,32 @@ import type { MatchRecord, Simplify } from "./Types.js"
1718
* import { pipe } from "effect/Function"
1819
*
1920
* assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, pick("a", "b")), { a: "a", b: 1 })
21+
* assert.deepStrictEqual(pick({ a: "a", b: 1, c: true }, "a", "b"), { a: "a", b: 1 })
2022
*
2123
* @since 2.0.0
2224
*/
23-
export const pick = <Keys extends Array<PropertyKey>>(
24-
...keys: Keys
25-
) =>
26-
<S extends { [K in Keys[number]]?: any }>(
27-
s: S
28-
): MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>> => {
29-
const out: any = {}
30-
for (const k of keys) {
31-
if (k in s) {
32-
out[k] = (s as any)[k]
25+
export const pick: {
26+
<Keys extends Array<PropertyKey>>(
27+
...keys: Keys
28+
): <S extends { [K in Keys[number]]?: any }>(
29+
s: S
30+
) => MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>>
31+
<S extends object, Keys extends Array<keyof S>>(
32+
s: S,
33+
...keys: Keys
34+
): MatchRecord<S, { [K in Keys[number]]?: S[K] }, Simplify<Pick<S, Keys[number]>>>
35+
} = dual(
36+
(args) => Predicate.isObject(args[0]),
37+
<S extends object, Keys extends Array<keyof S>>(s: S, ...keys: Keys) => {
38+
const out: any = {}
39+
for (const k of keys) {
40+
if (k in s) {
41+
out[k] = (s as any)[k]
42+
}
3343
}
44+
return out
3445
}
35-
return out
36-
}
46+
)
3747

3848
/**
3949
* Create a new object by omitting properties of an existing object.
@@ -43,19 +53,28 @@ export const pick = <Keys extends Array<PropertyKey>>(
4353
* import { pipe } from "effect/Function"
4454
*
4555
* assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, omit("c")), { a: "a", b: 1 })
56+
* assert.deepStrictEqual(omit({ a: "a", b: 1, c: true }, "c"), { a: "a", b: 1 })
4657
*
4758
* @since 2.0.0
4859
*/
49-
export const omit = <Keys extends Array<PropertyKey>>(
50-
...keys: Keys
51-
) =>
52-
<S extends { [K in Keys[number]]?: any }>(s: S): Simplify<Omit<S, Keys[number]>> => {
53-
const out: any = { ...s }
54-
for (const k of keys) {
55-
delete out[k]
60+
export const omit: {
61+
<Keys extends Array<PropertyKey>>(
62+
...keys: Keys
63+
): <S extends { [K in Keys[number]]?: any }>(s: S) => Simplify<Omit<S, Keys[number]>>
64+
<S extends object, Keys extends Array<keyof S>>(
65+
s: S,
66+
...keys: Keys
67+
): Simplify<Omit<S, Keys[number]>>
68+
} = dual(
69+
(args) => Predicate.isObject(args[0]),
70+
<S extends object, Keys extends Array<keyof S>>(s: S, ...keys: Keys) => {
71+
const out: any = { ...s }
72+
for (const k of keys) {
73+
delete out[k]
74+
}
75+
return out
5676
}
57-
return out
58-
}
77+
)
5978

6079
/**
6180
* Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct

‎packages/effect/test/Struct.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ describe("Struct", () => {
1111

1212
it("pick", () => {
1313
expect(pipe({ a: "a", b: 1, c: true }, Struct.pick("a", "b"))).toEqual({ a: "a", b: 1 })
14+
expect(Struct.pick({ a: "a", b: 1, c: true }, "a", "b")).toEqual({ a: "a", b: 1 })
1415

1516
const record1: Record<string, number> = {}
1617
expect(pipe(record1, Struct.pick("a", "b"))).toStrictEqual({})
@@ -47,6 +48,7 @@ describe("Struct", () => {
4748

4849
it("omit", () => {
4950
expect(pipe({ a: "a", b: 1, c: true }, Struct.omit("c"))).toEqual({ a: "a", b: 1 })
51+
expect(pipe(Struct.omit({ a: "a", b: 1, c: true }, "c"))).toEqual({ a: "a", b: 1 })
5052

5153
const record1: Record<string, number> = {}
5254
expect(pipe(record1, Struct.omit("a", "c"))).toStrictEqual({})

0 commit comments

Comments
 (0)
Please sign in to comment.