diff --git a/.changeset/big-eyes-talk.md b/.changeset/big-eyes-talk.md new file mode 100644 index 0000000000..7c8c4cb32f --- /dev/null +++ b/.changeset/big-eyes-talk.md @@ -0,0 +1,5 @@ +--- +"@effect/schema": patch +--- + +Remove `Simplify` from `extend`, `pick`, `omit`, `pluck` APIs, closes #2989, #2990 diff --git a/packages/schema/dtslint/Context.ts b/packages/schema/dtslint/Context.ts index 6698a29382..67aec64433 100644 --- a/packages/schema/dtslint/Context.ts +++ b/packages/schema/dtslint/Context.ts @@ -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">, "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">, "aContext" | "bContext"> S.Struct({ a: aContext, b: bContext }).pipe(S.omit("b")) // --------------------------------------------- @@ -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<{ c: cContext; }>> diff --git a/packages/schema/dtslint/Schema.ts b/packages/schema/dtslint/Schema.ts index 7f86eb9c49..199b7785cd 100644 --- a/packages/schema/dtslint/Schema.ts +++ b/packages/schema/dtslint/Schema.ts @@ -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">, 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: 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 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 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 b: string; readonly c: boolean; readonly a?: string; }, "a" | "b">, never> pipe( S.Struct({ a: S.optional(S.String, { exact: true, default: () => "" }), @@ -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">, 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: 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 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 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 b: string; readonly c: boolean; readonly a?: string; }, "c">, never> pipe( S.Struct({ a: S.optional(S.String, { exact: true, default: () => "" }), @@ -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 })) @@ -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<{ 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, 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 })), @@ -1454,16 +1454,16 @@ S.asSchema(S.mutable(S.transform(S.Array(S.String), S.Array(S.String), { decode: // $ExpectType mutable, Array$>> 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))) // --------------------------------------------- diff --git a/packages/schema/dtslint/generic.ts b/packages/schema/dtslint/generic.ts new file mode 100644 index 0000000000..2dad72b345 --- /dev/null +++ b/packages/schema/dtslint/generic.ts @@ -0,0 +1,37 @@ +import { Schema } from "@effect/schema" +import { Either } from "effect" + +export const f1 = ( + resultSchema: Schema.Schema +) => { + const left = Schema.Struct({ + ok: Schema.Literal(false), + error: Schema.String + }) + const right = ( + resultSchema: Schema.Schema + ) => 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 + +export const f2 = (schema: Schema.Schema) => { + type Patch = Pick & Partial> + + const patch: Schema.Schema = schema.pipe( + Schema.pick("id"), + Schema.extend(schema.pipe(Schema.omit("id"), Schema.partial())) + ) + + return patch +} diff --git a/packages/schema/src/Schema.ts b/packages/schema/src/Schema.ts index dc1556231e..d7747ef1b6 100644 --- a/packages/schema/src/Schema.ts +++ b/packages/schema/src/Schema.ts @@ -2632,8 +2632,7 @@ export const Record = (key: K, value export const pick = >(...keys: Keys) => ( self: Schema -): SchemaClass>, Types.Simplify>, R> => - make(AST.pick(self.ast, keys)) +): SchemaClass, Pick, R> => make(AST.pick(self.ast, keys)) /** * @category struct transformations @@ -2642,8 +2641,7 @@ export const pick = >(...key export const omit = >(...keys: Keys) => ( self: Schema -): SchemaClass>, Types.Simplify>, R> => - make(AST.omit(self.ast, keys)) +): SchemaClass, Omit, R> => make(AST.omit(self.ast, keys)) /** * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, @@ -2686,7 +2684,7 @@ export const pluck: { ( schema: Schema, key: K - ): Schema>, R> => { + ): Schema, R> => { const ps = AST.getPropertyKeyIndexedAccess(AST.typeAST(schema.ast), key) const value = make(ps.isOptional ? AST.orUndefined(ps.type) : ps.type) return transform( @@ -2971,8 +2969,8 @@ const intersectUnionMembers = ( export interface extend extends AnnotableClass< extend, - Types.Simplify & Schema.Type>, - Types.Simplify & Schema.Encoded>, + Schema.Type & Schema.Type, + Schema.Encoded & Schema.Encoded, Schema.Context | Schema.Context > {} @@ -3007,19 +3005,11 @@ export interface extend extend * @since 0.67.0 */ export const extend: { - ( - that: That - ): (self: Self) => extend - ( - self: Self, - that: That - ): extend + (that: That): (self: Self) => extend + (self: Self, that: That): extend } = dual( 2, - ( - self: Self, - that: That - ) => make(extendAST(self.ast, that.ast, [])) + (self: Self, that: That) => make(extendAST(self.ast, that.ast, [])) ) /**