Skip to content

Commit

Permalink
Remove Simplify from extend, pick, omit, pluck APIs, closes… (
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored Jun 14, 2024
1 parent 07e12ec commit 2ee4f2b
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 39 deletions.
5 changes: 5 additions & 0 deletions .changeset/big-eyes-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/schema": patch
---

Remove `Simplify` from `extend`, `pick`, `omit`, `pluck` APIs, closes #2989, #2990
6 changes: 3 additions & 3 deletions packages/schema/dtslint/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,14 @@ S.Struct({ a: aContext, b: bContext })
// pick
// ---------------------------------------------

// $ExpectType SchemaClass<{ readonly a: string; }, { readonly a: string; }, "aContext" | "bContext">
// $ExpectType SchemaClass<Pick<{ readonly a: string; readonly b: number; }, "a">, Pick<{ readonly a: string; readonly b: number; }, "a">, "aContext" | "bContext">
S.Struct({ a: aContext, b: bContext }).pipe(S.pick("a"))

// ---------------------------------------------
// omit
// ---------------------------------------------

// $ExpectType SchemaClass<{ readonly a: string; }, { readonly a: string; }, "aContext" | "bContext">
// $ExpectType SchemaClass<Omit<{ readonly a: string; readonly b: number; }, "b">, Omit<{ readonly a: string; readonly b: number; }, "b">, "aContext" | "bContext">
S.Struct({ a: aContext, b: bContext }).pipe(S.omit("b"))

// ---------------------------------------------
Expand Down Expand Up @@ -267,7 +267,7 @@ S.Record(aContext, bContext)
// extend
// ---------------------------------------------

// $ExpectType Schema<{ readonly a: string; readonly b: number; readonly c: boolean; }, { readonly a: string; readonly b: number; readonly c: boolean; }, "aContext" | "bContext" | "cContext">
// $ExpectType Schema<{ readonly a: string; readonly b: number; } & { readonly c: boolean; }, { readonly a: string; readonly b: number; } & { readonly c: boolean; }, "aContext" | "bContext" | "cContext">
S.asSchema(S.Struct({ a: aContext, b: bContext }).pipe(S.extend(S.Struct({ c: cContext }))))

// $ExpectType extend<Struct<{ a: aContext; b: bContext; }>, Struct<{ c: cContext; }>>
Expand Down
36 changes: 18 additions & 18 deletions packages/schema/dtslint/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -863,29 +863,29 @@ S.Struct({ a: S.String.pipe(S.optional({ exact: true, nullable: true, as: "Optio
// @ts-expect-error
pipe(S.Struct({ a: S.propertySignature(S.Number).pipe(S.fromKey("c")) }), S.pick("a"))

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a: string; readonly b: number; }, never>
// $ExpectType SchemaClass<Pick<{ readonly a: string; readonly b: number; readonly c: boolean; }, "a" | "b">, Pick<{ readonly a: string; readonly b: number; readonly c: boolean; }, "a" | "b">, never>
pipe(S.Struct({ a: S.String, b: S.Number, c: S.Boolean }), S.pick("a", "b"))

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Pick<{ readonly a: string; readonly b: number; readonly c: boolean; }, "a" | "b">, Pick<{ readonly a: string; readonly b: string; readonly c: boolean; }, "a" | "b">, never>
pipe(S.Struct({ a: S.String, b: S.NumberFromString, c: S.Boolean }), S.pick("a", "b"))

// ---------------------------------------------
// pick - optional
// ---------------------------------------------

// $ExpectType SchemaClass<{ readonly a?: string; readonly b: number; }, { readonly a?: string; readonly b: number; }, never>
// $ExpectType SchemaClass<Pick<{ readonly a?: string; readonly b: number; readonly c: boolean; }, "a" | "b">, Pick<{ readonly b: number; readonly c: boolean; readonly a?: string; }, "a" | "b">, never>
pipe(
S.Struct({ a: S.optional(S.String, { exact: true }), b: S.Number, c: S.Boolean }),
S.pick("a", "b")
)

// $ExpectType SchemaClass<{ readonly a?: string; readonly b: number; }, { readonly a?: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Pick<{ readonly a?: string; readonly b: number; readonly c: boolean; }, "a" | "b">, Pick<{ readonly b: string; readonly c: boolean; readonly a?: string; }, "a" | "b">, never>
pipe(
S.Struct({ a: S.optional(S.String, { exact: true }), b: S.NumberFromString, c: S.Boolean }),
S.pick("a", "b")
)

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a?: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Pick<{ readonly a: string; readonly b: number; readonly c: boolean; }, "a" | "b">, Pick<{ readonly b: string; readonly c: boolean; readonly a?: string; }, "a" | "b">, never>
pipe(
S.Struct({
a: S.optional(S.String, { exact: true, default: () => "" }),
Expand All @@ -902,26 +902,26 @@ pipe(
// @ts-expect-error
pipe(S.Struct({ a: S.propertySignature(S.Number).pipe(S.fromKey("c")) }), S.omit("a"))

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a: string; readonly b: number; }, never>
// $ExpectType SchemaClass<Omit<{ readonly a: string; readonly b: number; readonly c: boolean; }, "c">, Omit<{ readonly a: string; readonly b: number; readonly c: boolean; }, "c">, never>
pipe(S.Struct({ a: S.String, b: S.Number, c: S.Boolean }), S.omit("c"))

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Omit<{ readonly a: string; readonly b: number; readonly c: boolean; }, "c">, Omit<{ readonly a: string; readonly b: string; readonly c: boolean; }, "c">, never>
pipe(S.Struct({ a: S.String, b: S.NumberFromString, c: S.Boolean }), S.omit("c"))

// ---------------------------------------------
// omit - optional
// ---------------------------------------------

// $ExpectType SchemaClass<{ readonly a?: string; readonly b: number; }, { readonly a?: string; readonly b: number; }, never>
// $ExpectType SchemaClass<Omit<{ readonly a?: string; readonly b: number; readonly c: boolean; }, "c">, Omit<{ readonly b: number; readonly c: boolean; readonly a?: string; }, "c">, never>
pipe(S.Struct({ a: S.optional(S.String, { exact: true }), b: S.Number, c: S.Boolean }), S.omit("c"))

// $ExpectType SchemaClass<{ readonly a?: string; readonly b: number; }, { readonly a?: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Omit<{ readonly a?: string; readonly b: number; readonly c: boolean; }, "c">, Omit<{ readonly b: string; readonly c: boolean; readonly a?: string; }, "c">, never>
pipe(
S.Struct({ a: S.optional(S.String, { exact: true }), b: S.NumberFromString, c: S.Boolean }),
S.omit("c")
)

// $ExpectType SchemaClass<{ readonly a: string; readonly b: number; }, { readonly a?: string; readonly b: string; }, never>
// $ExpectType SchemaClass<Omit<{ readonly a: string; readonly b: number; readonly c: boolean; }, "c">, Omit<{ readonly b: string; readonly c: boolean; readonly a?: string; }, "c">, never>
pipe(
S.Struct({
a: S.optional(S.String, { exact: true, default: () => "" }),
Expand Down Expand Up @@ -1058,7 +1058,7 @@ S.Record(S.String.pipe(S.brand(Symbol.for("UserId"))), S.String)
// extend
// ---------------------------------------------

// $ExpectType Schema<{ readonly a: string; readonly b: string; readonly c: string; }, { readonly a: string; readonly b: string; readonly c: string; }, never>
// $ExpectType Schema<{ readonly a: string; readonly b: string; } & { readonly c: string; }, { readonly a: string; readonly b: string; } & { readonly c: string; }, never>
S.asSchema(pipe(
S.Struct({ a: S.String, b: S.String }),
S.extend(S.Struct({ c: S.String }))
Expand All @@ -1070,19 +1070,19 @@ pipe(
S.extend(S.Struct({ c: S.String }))
)

// $ExpectType Schema<{ readonly a: string; readonly b: string; readonly c: string; }, { readonly a: string; readonly b: string; readonly c: string; }, never>
// $ExpectType Schema<{ readonly a: string; readonly b: string; } & { readonly c: string; }, { readonly a: string; readonly b: string; } & { readonly c: string; }, never>
S.asSchema(S.extend(S.Struct({ a: S.String, b: S.String }), S.Struct({ c: S.String })))

// $ExpectType extend<Struct<{ a: typeof String$; b: typeof String$; }>, Struct<{ c: typeof String$; }>>
S.extend(S.Struct({ a: S.String, b: S.String }), S.Struct({ c: S.String }))

// $ExpectType Schema<{ readonly a: string; readonly b: number; } | { readonly a: string; readonly c: boolean; }, { readonly a: string; readonly b: number; } | { readonly a: string; readonly c: boolean; }, never>
// $ExpectType Schema<{ readonly a: string; } & ({ readonly b: number; } | { readonly c: boolean; }), { readonly a: string; } & ({ readonly b: number; } | { readonly c: boolean; }), never>
S.asSchema(S.extend(S.Struct({ a: S.String }), S.Union(S.Struct({ b: S.Number }), S.Struct({ c: S.Boolean }))))

// $ExpectType extend<Struct<{ a: typeof String$; }>, Union<[Struct<{ b: typeof Number$; }>, Struct<{ c: typeof Boolean$; }>]>>
S.extend(S.Struct({ a: S.String }), S.Union(S.Struct({ b: S.Number }), S.Struct({ c: S.Boolean })))

// $ExpectType Schema<{ readonly [x: string]: string; readonly a: string; readonly b: string; readonly c: string; }, { readonly [x: string]: string; readonly a: string; readonly b: string; readonly c: string; }, never>
// $ExpectType Schema<{ readonly a: string; readonly b: string; } & { readonly c: string; } & { readonly [x: string]: string; }, { readonly a: string; readonly b: string; } & { readonly c: string; } & { readonly [x: string]: string; }, never>
S.asSchema(pipe(
S.Struct({ a: S.String, b: S.String }),
S.extend(S.Struct({ c: S.String })),
Expand Down Expand Up @@ -1454,16 +1454,16 @@ S.asSchema(S.mutable(S.transform(S.Array(S.String), S.Array(S.String), { decode:
// $ExpectType mutable<transform<Array$<typeof String$>, Array$<typeof String$>>>
S.mutable(S.transform(S.Array(S.String), S.Array(S.String), { decode: identity, encode: identity }))

// $ExpectType Schema<{ a: string; b: number; }, { a: string; b: number; }, never>
// $ExpectType Schema<{ a: string; } & { b: number; }, { a: string; } & { b: number; }, never>
S.asSchema(S.extend(S.mutable(S.Struct({ a: S.String })), S.mutable(S.Struct({ b: S.Number }))))

// $ExpectType Schema<{ a: string; readonly b: number; }, { a: string; readonly b: number; }, never>
// $ExpectType Schema<{ a: string; } & { readonly b: number; }, { a: string; } & { readonly b: number; }, never>
S.asSchema(S.extend(S.mutable(S.Struct({ a: S.String })), S.Struct({ b: S.Number })))

// $ExpectType Schema<{ [x: string]: string; a: string; }, { [x: string]: string; a: string; }, never>
// $ExpectType Schema<{ a: string; } & { [x: string]: string; }, { a: string; } & { [x: string]: string; }, never>
S.asSchema(S.extend(S.mutable(S.Struct({ a: S.String })), S.mutable(S.Record(S.String, S.String))))

// $ExpectType Schema<{ readonly [x: string]: string; a: string; }, { readonly [x: string]: string; a: string; }, never>
// $ExpectType Schema<{ a: string; } & { readonly [x: string]: string; }, { a: string; } & { readonly [x: string]: string; }, never>
S.asSchema(S.extend(S.mutable(S.Struct({ a: S.String })), S.Record(S.String, S.String)))

// ---------------------------------------------
Expand Down
37 changes: 37 additions & 0 deletions packages/schema/dtslint/generic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Schema } from "@effect/schema"
import { Either } from "effect"

export const f1 = <A extends object, I extends object, R>(
resultSchema: Schema.Schema<A, I, R>
) => {
const left = Schema.Struct({
ok: Schema.Literal(false),
error: Schema.String
})
const right = <A, I, R>(
resultSchema: Schema.Schema<A, I, R>
) => Schema.extend(Schema.Struct({ ok: Schema.Literal(true) }), resultSchema)
const union = Schema.Union(left, right(resultSchema))
const out = Schema.transform(
union,
Schema.EitherFromSelf({ left: Schema.String, right: Schema.typeSchema(resultSchema) }),
{
decode: (u) => u.ok ? Either.right(u) : Either.left(u.error),
encode: (a) => ({ ok: true as const, ...a })
}
)
return out
}

type Model = { id: string } & Record<string, unknown>

export const f2 = <T extends Model>(schema: Schema.Schema<T>) => {
type Patch = Pick<T, "id"> & Partial<Omit<T, "id">>

const patch: Schema.Schema<Patch> = schema.pipe(
Schema.pick("id"),
Schema.extend(schema.pipe(Schema.omit("id"), Schema.partial()))
)

return patch
}
26 changes: 8 additions & 18 deletions packages/schema/src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2632,8 +2632,7 @@ export const Record = <K extends Schema.All, V extends Schema.All>(key: K, value
export const pick = <A, I, Keys extends ReadonlyArray<keyof A & keyof I>>(...keys: Keys) =>
<R>(
self: Schema<A, I, R>
): SchemaClass<Types.Simplify<Pick<A, Keys[number]>>, Types.Simplify<Pick<I, Keys[number]>>, R> =>
make(AST.pick(self.ast, keys))
): SchemaClass<Pick<A, Keys[number]>, Pick<I, Keys[number]>, R> => make(AST.pick(self.ast, keys))

/**
* @category struct transformations
Expand All @@ -2642,8 +2641,7 @@ export const pick = <A, I, Keys extends ReadonlyArray<keyof A & keyof I>>(...key
export const omit = <A, I, Keys extends ReadonlyArray<keyof A & keyof I>>(...keys: Keys) =>
<R>(
self: Schema<A, I, R>
): SchemaClass<Types.Simplify<Omit<A, Keys[number]>>, Types.Simplify<Omit<I, Keys[number]>>, R> =>
make(AST.omit(self.ast, keys))
): SchemaClass<Omit<A, Keys[number]>, Omit<I, Keys[number]>, R> => make(AST.omit(self.ast, keys))

/**
* Given a schema `Schema<A, I, R>` and a key `key: K`, this function extracts a specific field from the `A` type,
Expand Down Expand Up @@ -2686,7 +2684,7 @@ export const pluck: {
<A, I, R, K extends keyof A & keyof I>(
schema: Schema<A, I, R>,
key: K
): Schema<A[K], Types.Simplify<Pick<I, K>>, R> => {
): Schema<A[K], Pick<I, K>, R> => {
const ps = AST.getPropertyKeyIndexedAccess(AST.typeAST(schema.ast), key)
const value = make<A[K], A[K], R>(ps.isOptional ? AST.orUndefined(ps.type) : ps.type)
return transform(
Expand Down Expand Up @@ -2971,8 +2969,8 @@ const intersectUnionMembers = (
export interface extend<Self extends Schema.Any, That extends Schema.Any> extends
AnnotableClass<
extend<Self, That>,
Types.Simplify<Schema.Type<Self> & Schema.Type<That>>,
Types.Simplify<Schema.Encoded<Self> & Schema.Encoded<That>>,
Schema.Type<Self> & Schema.Type<That>,
Schema.Encoded<Self> & Schema.Encoded<That>,
Schema.Context<Self> | Schema.Context<That>
>
{}
Expand Down Expand Up @@ -3007,19 +3005,11 @@ export interface extend<Self extends Schema.Any, That extends Schema.Any> extend
* @since 0.67.0
*/
export const extend: {
<That extends Schema.Any>(
that: That
): <Self extends Schema.Any>(self: Self) => extend<Self, That>
<Self extends Schema.Any, That extends Schema.Any>(
self: Self,
that: That
): extend<Self, That>
<That extends Schema.Any>(that: That): <Self extends Schema.Any>(self: Self) => extend<Self, That>
<Self extends Schema.Any, That extends Schema.Any>(self: Self, that: That): extend<Self, That>
} = dual(
2,
<Self extends Schema.Any, That extends Schema.Any>(
self: Self,
that: That
) => make(extendAST(self.ast, that.ast, []))
<Self extends Schema.Any, That extends Schema.Any>(self: Self, that: That) => make(extendAST(self.ast, that.ast, []))
)

/**
Expand Down

0 comments on commit 2ee4f2b

Please sign in to comment.