Skip to content

Commit fb798eb

Browse files
authoredFeb 25, 2025··
Schema: More Accurate Return Types (#4509)
1 parent f2aee98 commit fb798eb

File tree

3 files changed

+244
-110
lines changed

3 files changed

+244
-110
lines changed
 

‎.changeset/flat-actors-battle.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Schema: More Accurate Return Types for:
6+
7+
- `transformLiteral`
8+
- `clamp`
9+
- `clampBigInt`
10+
- `clampDuration`
11+
- `clampBigDecimal`
12+
- `head`
13+
- `headNonEmpty`
14+
- `headOrElse`

‎packages/effect/dtslint/Schema/Schema.tst.ts

+161-66
Original file line numberDiff line numberDiff line change
@@ -1976,14 +1976,20 @@ describe("Schema", () => {
19761976
})
19771977

19781978
it("transformLiteral", () => {
1979-
expect(S.asSchema(S.transformLiteral(0, "a"))).type.toBe<S.Schema<"a", 0>>()
1980-
expect(S.transformLiteral(0, "a")).type.toBe<S.transformLiteral<"a", 0>>()
1979+
const schema = S.transformLiteral(0, "a")
1980+
expect(S.asSchema(schema)).type.toBe<S.Schema<"a", 0>>()
1981+
expect(schema).type.toBe<S.transformLiteral<"a", 0>>()
1982+
expect(schema.annotations({})).type.toBe<S.transformLiteral<"a", 0>>()
1983+
expect(schema.from).type.toBe<S.Literal<[0]>>()
1984+
expect(schema.to).type.toBe<S.Literal<["a"]>>()
19811985
})
19821986

19831987
it("transformLiterals", () => {
1984-
expect(S.asSchema(S.transformLiterals([0, "a"], [1, "b"]))).type.toBe<S.Schema<"a" | "b", 0 | 1>>()
1985-
expect(S.transformLiterals([0, "a"], [1, "b"]))
1986-
.type.toBe<S.Union<[S.transformLiteral<"a", 0>, S.transformLiteral<"b", 1>]>>()
1988+
const schema = S.transformLiterals([0, "a"], [1, "b"])
1989+
expect(S.asSchema(schema)).type.toBe<S.Schema<"a" | "b", 0 | 1>>()
1990+
expect(schema).type.toBe<S.Union<[S.transformLiteral<"a", 0>, S.transformLiteral<"b", 1>]>>()
1991+
expect(schema.annotations({})).type.toBe<S.Union<[S.transformLiteral<"a", 0>, S.transformLiteral<"b", 1>]>>()
1992+
19871993
expect(S.transformLiterals([0, "a"])).type.toBe<S.transformLiteral<"a", 0>>()
19881994
const pairs = hole<Array<readonly [0 | 1, "a" | "b"]>>()
19891995
expect(S.transformLiterals(...pairs)).type.toBe<S.Schema<"a" | "b", 0 | 1>>()
@@ -1998,67 +2004,6 @@ describe("Schema", () => {
19982004
expect(S.optional(S.String).annotations({})).type.toBe<S.optional<typeof S.String>>()
19992005
})
20002006

2001-
it("pluck", () => {
2002-
// @ts-expect-error
2003-
S.pluck(S.Struct({ a: S.propertySignature(S.Number).pipe(S.fromKey("c")) }), "a")
2004-
expect(S.pluck(S.Struct({ a: S.String, b: S.Number }), "a"))
2005-
.type.toBe<S.Schema<string, { readonly a: string }>>()
2006-
expect(pipe(S.Struct({ a: S.String, b: S.Number }), S.pluck("a")))
2007-
.type.toBe<S.Schema<string, { readonly a: string }>>()
2008-
expect(S.pluck(S.Struct({ a: S.optional(S.String), b: S.Number }), "a"))
2009-
.type.toBe<S.Schema<string | undefined, { readonly a?: string | undefined }>>()
2010-
expect(pipe(S.Struct({ a: S.optional(S.String), b: S.Number }), S.pluck("a")))
2011-
.type.toBe<S.Schema<string | undefined, { readonly a?: string | undefined }>>()
2012-
expect(S.pluck(S.Struct({ a: S.optionalWith(S.String, { exact: true }), b: S.Number }), "a"))
2013-
.type.toBe<S.Schema<string | undefined, { readonly a?: string }>>()
2014-
expect(pipe(S.Struct({ a: S.optionalWith(S.String, { exact: true }), b: S.Number }), S.pluck("a")))
2015-
.type.toBe<S.Schema<string | undefined, { readonly a?: string }>>()
2016-
})
2017-
2018-
it("head", () => {
2019-
const schema = S.head(S.Array(S.Number))
2020-
expect(schema).type.toBe<
2021-
S.transform<
2022-
S.Schema<ReadonlyArray<number>>,
2023-
S.OptionFromSelf<S.SchemaClass<number>>
2024-
>
2025-
>()
2026-
expect(schema.annotations({})).type.toBe<
2027-
S.transform<
2028-
S.Schema<ReadonlyArray<number>>,
2029-
S.OptionFromSelf<S.SchemaClass<number>>
2030-
>
2031-
>()
2032-
expect(schema.from).type.toBe<S.Schema<ReadonlyArray<number>>>()
2033-
expect(schema.to).type.toBe<S.OptionFromSelf<S.SchemaClass<number>>>()
2034-
})
2035-
2036-
it("headNonEmpty", () => {
2037-
const schema = S.headNonEmpty(S.NonEmptyArray(S.Number))
2038-
expect(schema).type.toBe<
2039-
S.transform<
2040-
S.Schema<readonly [number, ...Array<number>]>,
2041-
S.SchemaClass<number>
2042-
>
2043-
>()
2044-
expect(schema.annotations({})).type.toBe<
2045-
S.transform<
2046-
S.Schema<readonly [number, ...Array<number>]>,
2047-
S.SchemaClass<number>
2048-
>
2049-
>()
2050-
expect(schema.from).type.toBe<S.Schema<readonly [number, ...Array<number>]>>()
2051-
expect(schema.to).type.toBe<S.SchemaClass<number>>()
2052-
})
2053-
2054-
it("headOrElse", () => {
2055-
const schema = S.headOrElse(S.Array(S.Number))
2056-
expect(schema).type.toBe<S.transform<S.Schema<ReadonlyArray<number>>, S.SchemaClass<number>>>()
2057-
expect(schema.annotations({})).type.toBe<S.transform<S.Schema<ReadonlyArray<number>>, S.SchemaClass<number>>>()
2058-
expect(schema.from).type.toBe<S.Schema<ReadonlyArray<number>>>()
2059-
expect(schema.to).type.toBe<S.SchemaClass<number>>()
2060-
})
2061-
20622007
it("TaggedClass", () => {
20632008
class MyTaggedClass extends S.TaggedClass<MyTaggedClass>()("MyTaggedClass", {
20642009
a: S.String
@@ -3848,4 +3793,154 @@ describe("Schema", () => {
38483793
expect(schema.from).type.toBe<S.Union<[typeof S.NumberFromString, S.NonEmptyArray<typeof S.NumberFromString>]>>()
38493794
expect(schema.to).type.toBe<S.SchemaClass<readonly [number, ...Array<number>]>>()
38503795
})
3796+
3797+
it("ReadonlyMapFromRecord", () => {
3798+
const schema = S.ReadonlyMapFromRecord({ key: S.NumberFromString, value: S.NumberFromString })
3799+
expect(S.asSchema(schema)).type.toBe<S.Schema<ReadonlyMap<number, number>, { readonly [x: string]: string }>>()
3800+
expect(schema).type.toBe<S.SchemaClass<ReadonlyMap<number, number>, { readonly [x: string]: string }>>()
3801+
expect(schema.annotations({})).type.toBe<
3802+
S.SchemaClass<ReadonlyMap<number, number>, { readonly [x: string]: string }>
3803+
>()
3804+
})
3805+
3806+
it("MapFromRecord", () => {
3807+
const schema = S.MapFromRecord({ key: S.NumberFromString, value: S.NumberFromString })
3808+
expect(S.asSchema(schema)).type.toBe<S.Schema<Map<number, number>, { readonly [x: string]: string }>>()
3809+
expect(schema).type.toBe<S.SchemaClass<Map<number, number>, { readonly [x: string]: string }>>()
3810+
expect(schema.annotations({})).type.toBe<S.SchemaClass<Map<number, number>, { readonly [x: string]: string }>>()
3811+
})
3812+
3813+
describe("Transformations", () => {
3814+
it("clamp", () => {
3815+
// @ts-expect-error: Type 'string' is not assignable to type 'number'
3816+
S.String.pipe(S.clamp(-1, 1))
3817+
3818+
const schema = S.Number.pipe(S.clamp(-1, 1))
3819+
expect(S.asSchema(schema)).type.toBe<S.Schema<number>>()
3820+
expect(schema).type.toBe<S.transform<typeof S.Number, S.filter<S.SchemaClass<number>>>>()
3821+
expect(schema.annotations({})).type.toBe<S.transform<typeof S.Number, S.filter<S.SchemaClass<number>>>>()
3822+
expect(schema.from).type.toBe<typeof S.Number>()
3823+
expect(schema.to).type.toBe<S.filter<S.SchemaClass<number>>>()
3824+
})
3825+
3826+
it("clampBigInt", () => {
3827+
// @ts-expect-error: Type 'string' is not assignable to type 'bigint'
3828+
S.String.pipe(S.clampBigInt(-1, 1))
3829+
3830+
const schema = S.BigIntFromSelf.pipe(S.clampBigInt(-1n, 1n))
3831+
expect(S.asSchema(schema)).type.toBe<S.Schema<bigint>>()
3832+
expect(schema).type.toBe<S.transform<typeof S.BigIntFromSelf, S.filter<S.SchemaClass<bigint>>>>()
3833+
expect(schema.annotations({})).type.toBe<
3834+
S.transform<typeof S.BigIntFromSelf, S.filter<S.SchemaClass<bigint>>>
3835+
>()
3836+
expect(schema.from).type.toBe<typeof S.BigIntFromSelf>()
3837+
expect(schema.to).type.toBe<S.filter<S.SchemaClass<bigint>>>()
3838+
})
3839+
3840+
it("clampDuration", () => {
3841+
// @ts-expect-error: Type 'string' is not assignable to type 'Duration'
3842+
S.String.pipe(S.clampDuration(-1, 1))
3843+
3844+
const schema = S.DurationFromSelf.pipe(S.clampDuration(-1, 1))
3845+
expect(S.asSchema(schema)).type.toBe<S.Schema<Duration.Duration>>()
3846+
expect(schema).type.toBe<S.transform<typeof S.DurationFromSelf, S.filter<S.SchemaClass<Duration.Duration>>>>()
3847+
expect(schema.annotations({})).type.toBe<
3848+
S.transform<typeof S.DurationFromSelf, S.filter<S.SchemaClass<Duration.Duration>>>
3849+
>()
3850+
expect(schema.from).type.toBe<typeof S.DurationFromSelf>()
3851+
expect(schema.to).type.toBe<S.filter<S.SchemaClass<Duration.Duration>>>()
3852+
})
3853+
3854+
it("clampBigDecimal", () => {
3855+
// @ts-expect-error: Type 'string' is not assignable to type 'BigDecimal'
3856+
S.String.pipe(S.clampBigDecimal(-1, 1))
3857+
3858+
const schema = S.BigDecimalFromSelf.pipe(
3859+
S.clampBigDecimal(hole<BigDecimal.BigDecimal>(), hole<BigDecimal.BigDecimal>())
3860+
)
3861+
expect(S.asSchema(schema)).type.toBe<S.Schema<BigDecimal.BigDecimal>>()
3862+
expect(schema).type.toBe<
3863+
S.transform<typeof S.BigDecimalFromSelf, S.filter<S.SchemaClass<BigDecimal.BigDecimal>>>
3864+
>()
3865+
expect(schema.annotations({})).type.toBe<
3866+
S.transform<typeof S.BigDecimalFromSelf, S.filter<S.SchemaClass<BigDecimal.BigDecimal>>>
3867+
>()
3868+
expect(schema.from).type.toBe<typeof S.BigDecimalFromSelf>()
3869+
expect(schema.to).type.toBe<S.filter<S.SchemaClass<BigDecimal.BigDecimal>>>()
3870+
})
3871+
3872+
it("head", () => {
3873+
// @ts-expect-error: Type 'string' is not assignable to type 'readonly unknown[]'
3874+
S.String.pipe(S.head)
3875+
3876+
const schema = S.head(S.Array(S.NumberFromString))
3877+
3878+
expect(S.asSchema(schema)).type.toBe<S.Schema<Option.Option<number>, ReadonlyArray<string>, never>>()
3879+
expect(schema)
3880+
.type.toBe<S.transform<S.Array$<typeof S.NumberFromString>, S.OptionFromSelf<S.SchemaClass<number>>>>()
3881+
expect(schema.annotations({}))
3882+
.type.toBe<S.transform<S.Array$<typeof S.NumberFromString>, S.OptionFromSelf<S.SchemaClass<number>>>>()
3883+
expect(schema.from).type.toBe<S.Array$<typeof S.NumberFromString>>()
3884+
expect(schema.to).type.toBe<S.OptionFromSelf<S.SchemaClass<number>>>()
3885+
})
3886+
3887+
it("headNonEmpty", () => {
3888+
// @ts-expect-error: Type 'string' is not assignable to type 'readonly [unknown, ...unknown[]]'
3889+
S.String.pipe(S.headNonEmpty)
3890+
3891+
const schema = S.headNonEmpty(S.NonEmptyArray(S.Number))
3892+
expect(S.asSchema(schema)).type.toBe<S.Schema<number, readonly [number, ...Array<number>]>>()
3893+
expect(schema)
3894+
.type.toBe<S.transform<S.NonEmptyArray<typeof S.Number>, S.SchemaClass<number>>>()
3895+
expect(schema.annotations({}))
3896+
.type.toBe<S.transform<S.NonEmptyArray<typeof S.Number>, S.SchemaClass<number>>>()
3897+
expect(schema.from).type.toBe<S.NonEmptyArray<typeof S.Number>>()
3898+
expect(schema.to).type.toBe<S.SchemaClass<number>>()
3899+
})
3900+
3901+
it("headOrElse", () => {
3902+
// @ts-expect-error: Type 'string' is not assignable to type 'readonly unknown[]'
3903+
S.String.pipe(S.headOrElse())
3904+
S.headOrElse(
3905+
S.Array(S.Number),
3906+
// @ts-expect-error: Type 'string' is not assignable to type 'number'
3907+
() => "a"
3908+
)
3909+
S.Array(S.Number).pipe(S.headOrElse(
3910+
// @ts-expect-error: Type 'number' is not assignable to type 'string'
3911+
() => "a"
3912+
))
3913+
3914+
const schema = S.headOrElse(S.Array(S.Number))
3915+
expect(S.asSchema(schema)).type.toBe<S.Schema<number, ReadonlyArray<number>>>()
3916+
expect(schema).type.toBe<S.transform<S.Array$<typeof S.Number>, S.SchemaClass<number>>>()
3917+
expect(schema.annotations({})).type.toBe<S.transform<S.Array$<typeof S.Number>, S.SchemaClass<number>>>()
3918+
expect(schema.from).type.toBe<S.Array$<typeof S.Number>>()
3919+
expect(schema.to).type.toBe<S.SchemaClass<number>>()
3920+
})
3921+
3922+
it("pluck", () => {
3923+
S.pluck(
3924+
S.Struct({ a: S.propertySignature(S.Number).pipe(S.fromKey("c")) }),
3925+
// @ts-expect-error: Argument of type '"a"' is not assignable to parameter of type 'never'
3926+
"a"
3927+
)
3928+
3929+
expect(pipe(S.Struct({ a: S.String, b: S.Number }), S.pluck("a")))
3930+
.type.toBe<S.SchemaClass<string, { readonly a: string }>>()
3931+
const schema = S.pluck(S.Struct({ a: S.String, b: S.Number }), "a")
3932+
expect(schema).type.toBe<S.SchemaClass<string, { readonly a: string }>>()
3933+
expect(schema.annotations({})).type.toBe<S.SchemaClass<string, { readonly a: string }>>()
3934+
3935+
// should support optional fields
3936+
expect(S.pluck(S.Struct({ a: S.optional(S.String), b: S.Number }), "a"))
3937+
.type.toBe<S.SchemaClass<string | undefined, { readonly a?: string | undefined }>>()
3938+
expect(pipe(S.Struct({ a: S.optional(S.String), b: S.Number }), S.pluck("a")))
3939+
.type.toBe<S.SchemaClass<string | undefined, { readonly a?: string | undefined }>>()
3940+
expect(S.pluck(S.Struct({ a: S.optionalWith(S.String, { exact: true }), b: S.Number }), "a"))
3941+
.type.toBe<S.SchemaClass<string | undefined, { readonly a?: string }>>()
3942+
expect(pipe(S.Struct({ a: S.optionalWith(S.String, { exact: true }), b: S.Number }), S.pluck("a")))
3943+
.type.toBe<S.SchemaClass<string | undefined, { readonly a?: string }>>()
3944+
})
3945+
})
38513946
})

‎packages/effect/src/Schema.ts

+69-44
Original file line numberDiff line numberDiff line change
@@ -3033,11 +3033,11 @@ export const omit = <A, I, Keys extends ReadonlyArray<keyof A & keyof I>>(...key
30333033
export const pluck: {
30343034
<A, I, K extends keyof A & keyof I>(
30353035
key: K
3036-
): <R>(schema: Schema<A, I, R>) => Schema<A[K], Simplify<Pick<I, K>>, R>
3036+
): <R>(schema: Schema<A, I, R>) => SchemaClass<A[K], Simplify<Pick<I, K>>, R>
30373037
<A, I, R, K extends keyof A & keyof I>(
30383038
schema: Schema<A, I, R>,
30393039
key: K
3040-
): Schema<A[K], Simplify<Pick<I, K>>, R>
3040+
): SchemaClass<A[K], Simplify<Pick<I, K>>, R>
30413041
} = dual(
30423042
2,
30433043
<A, I, R, K extends keyof A & keyof I>(
@@ -3046,7 +3046,7 @@ export const pluck: {
30463046
): Schema<A[K], Pick<I, K>, R> => {
30473047
const ps = AST.getPropertyKeyIndexedAccess(AST.typeAST(schema.ast), key)
30483048
const value = make<A[K], A[K], R>(ps.isOptional ? AST.orUndefined(ps.type) : ps.type)
3049-
return transform(
3049+
const out = transform(
30503050
schema.pipe(pick(key)),
30513051
value,
30523052
{
@@ -3055,6 +3055,7 @@ export const pluck: {
30553055
encode: (ak) => ps.isOptional && ak === undefined ? {} : { [key]: ak } as any
30563056
}
30573057
)
3058+
return out
30583059
}
30593060
)
30603061

@@ -3900,7 +3901,11 @@ export const transform: {
39003901
* @category api interface
39013902
* @since 3.10.0
39023903
*/
3903-
export interface transformLiteral<Type, Encoded> extends Annotable<transformLiteral<Type, Encoded>, Type, Encoded> {}
3904+
export interface transformLiteral<Type extends AST.LiteralValue, Encoded extends AST.LiteralValue>
3905+
extends transform<Literal<[Encoded]>, Literal<[Type]>>
3906+
{
3907+
annotations(annotations: Annotations.Schema<Type>): transformLiteral<Type, Encoded>
3908+
}
39043909

39053910
/**
39063911
* Creates a new `Schema` which transforms literal values.
@@ -3917,11 +3922,12 @@ export interface transformLiteral<Type, Encoded> extends Annotable<transformLite
39173922
* @category constructors
39183923
* @since 3.10.0
39193924
*/
3920-
export const transformLiteral = <Encoded extends AST.LiteralValue, Type extends AST.LiteralValue>(
3925+
export function transformLiteral<Encoded extends AST.LiteralValue, Type extends AST.LiteralValue>(
39213926
from: Encoded,
39223927
to: Type
3923-
): transformLiteral<Type, Encoded> =>
3924-
transform(Literal(from), Literal(to), { strict: true, decode: () => to, encode: () => from })
3928+
): transformLiteral<Type, Encoded> {
3929+
return transform(Literal(from), Literal(to), { strict: true, decode: () => to, encode: () => from })
3930+
}
39253931

39263932
/**
39273933
* Creates a new `Schema` which maps between corresponding literal values.
@@ -5159,14 +5165,16 @@ export const nonNegative = <S extends Schema.Any>(
51595165
* @category number transformations
51605166
* @since 3.10.0
51615167
*/
5162-
export const clamp =
5163-
(minimum: number, maximum: number) =>
5164-
<A extends number, I, R>(self: Schema<A, I, R>): transform<Schema<A, I, R>, filter<Schema<A>>> =>
5165-
transform(
5166-
self,
5167-
self.pipe(typeSchema, between(minimum, maximum)),
5168-
{ strict: false, decode: (self) => number_.clamp(self, { minimum, maximum }), encode: identity }
5169-
)
5168+
export const clamp = (minimum: number, maximum: number) =>
5169+
<S extends Schema.Any, A extends number>(
5170+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
5171+
): transform<S, filter<SchemaClass<A>>> => {
5172+
return transform(
5173+
self,
5174+
typeSchema(self).pipe(between(minimum, maximum)),
5175+
{ strict: false, decode: (self) => number_.clamp(self, { minimum, maximum }), encode: identity }
5176+
)
5177+
}
51705178

51715179
/**
51725180
* Transforms a `string` into a `number` by parsing the string using the `parse`
@@ -5542,14 +5550,15 @@ export const nonPositiveBigInt = <S extends Schema.Any>(
55425550
* @category bigint transformations
55435551
* @since 3.10.0
55445552
*/
5545-
export const clampBigInt =
5546-
(minimum: bigint, maximum: bigint) =>
5547-
<A extends bigint, I, R>(self: Schema<A, I, R>): transform<Schema<A, I, R>, filter<Schema<A>>> =>
5548-
transform(
5549-
self,
5550-
self.pipe(typeSchema, betweenBigInt(minimum, maximum)),
5551-
{ strict: false, decode: (self) => bigInt_.clamp(self, { minimum, maximum }), encode: identity }
5552-
)
5553+
export const clampBigInt = (minimum: bigint, maximum: bigint) =>
5554+
<S extends Schema.Any, A extends bigint>(
5555+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
5556+
): transform<S, filter<SchemaClass<A>>> =>
5557+
transform(
5558+
self,
5559+
self.pipe(typeSchema, betweenBigInt(minimum, maximum)),
5560+
{ strict: false, decode: (self) => bigInt_.clamp(self, { minimum, maximum }), encode: identity }
5561+
)
55535562

55545563
/** @ignore */
55555564
class BigInt$ extends transformOrFail(
@@ -5908,7 +5917,9 @@ export class Duration extends transform(
59085917
*/
59095918
export const clampDuration =
59105919
(minimum: duration_.DurationInput, maximum: duration_.DurationInput) =>
5911-
<A extends duration_.Duration, I, R>(self: Schema<A, I, R>): transform<Schema<A, I, R>, filter<Schema<A>>> =>
5920+
<S extends Schema.Any, A extends duration_.Duration>(
5921+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
5922+
): transform<S, filter<SchemaClass<A>>> =>
59125923
transform(
59135924
self,
59145925
self.pipe(typeSchema, betweenDuration(minimum, maximum)),
@@ -6377,29 +6388,39 @@ export const getNumberIndexedAccess = <A extends ReadonlyArray<any>, I extends R
63776388
* @category ReadonlyArray transformations
63786389
* @since 3.10.0
63796390
*/
6380-
export const head = <A, I, R>(
6381-
self: Schema<ReadonlyArray<A>, I, R>
6382-
): transform<Schema<ReadonlyArray<A>, I, R>, OptionFromSelf<SchemaClass<A>>> =>
6383-
transform(
6391+
export function head<S extends Schema.Any, A extends ReadonlyArray<unknown>>(
6392+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
6393+
): transform<S, OptionFromSelf<SchemaClass<A[number]>>> {
6394+
return transform(
63846395
self,
63856396
OptionFromSelf(getNumberIndexedAccess(typeSchema(self))),
6386-
{ strict: true, decode: array_.head, encode: option_.match({ onNone: () => [], onSome: array_.of }) }
6397+
{
6398+
strict: false,
6399+
decode: array_.head,
6400+
encode: option_.match({ onNone: () => [], onSome: array_.of })
6401+
}
63876402
)
6403+
}
63886404

63896405
/**
63906406
* Get the first element of a `NonEmptyReadonlyArray`.
63916407
*
63926408
* @category NonEmptyReadonlyArray transformations
63936409
* @since 3.12.0
63946410
*/
6395-
export const headNonEmpty = <A, I, R>(
6396-
self: Schema<array_.NonEmptyReadonlyArray<A>, I, R>
6397-
): transform<Schema<readonly [A, ...Array<A>], I, R>, SchemaClass<A>> =>
6398-
transform(
6411+
export function headNonEmpty<S extends Schema.Any, A extends array_.NonEmptyReadonlyArray<unknown>>(
6412+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
6413+
): transform<S, SchemaClass<A[number]>> {
6414+
return transform(
63996415
self,
64006416
getNumberIndexedAccess(typeSchema(self)),
6401-
{ strict: true, decode: array_.headNonEmpty, encode: array_.of }
6417+
{
6418+
strict: false,
6419+
decode: array_.headNonEmpty,
6420+
encode: (x: A[number]) => array_.of(x)
6421+
}
64026422
)
6423+
}
64036424

64046425
/**
64056426
* Retrieves the first element of a `ReadonlyArray`.
@@ -6410,13 +6431,15 @@ export const headNonEmpty = <A, I, R>(
64106431
* @since 3.10.0
64116432
*/
64126433
export const headOrElse: {
6413-
<A>(
6414-
fallback?: LazyArg<A>
6415-
): <I, R>(self: Schema<ReadonlyArray<A>, I, R>) => transform<Schema<ReadonlyArray<A>, I, R>, SchemaClass<A>>
6416-
<A, I, R>(
6417-
self: Schema<ReadonlyArray<A>, I, R>,
6418-
fallback?: LazyArg<A>
6419-
): transform<Schema<ReadonlyArray<A>, I, R>, SchemaClass<A>>
6434+
<S extends Schema.Any, A extends ReadonlyArray<unknown>>(
6435+
fallback?: LazyArg<A[number]>
6436+
): (
6437+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
6438+
) => transform<S, SchemaClass<A[number]>>
6439+
<S extends Schema.Any, A extends ReadonlyArray<unknown>>(
6440+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>,
6441+
fallback?: LazyArg<A[number]>
6442+
): transform<S, SchemaClass<A[number]>>
64206443
} = dual(
64216444
(args) => isSchema(args[0]),
64226445
<A, I, R>(
@@ -7535,7 +7558,7 @@ export {
75357558
export const ReadonlyMapFromRecord = <KA, KR, VA, VI, VR>({ key, value }: {
75367559
key: Schema<KA, string, KR>
75377560
value: Schema<VA, VI, VR>
7538-
}): Schema<ReadonlyMap<KA, VA>, { readonly [x: string]: VI }, KR | VR> =>
7561+
}): SchemaClass<ReadonlyMap<KA, VA>, { readonly [x: string]: VI }, KR | VR> =>
75397562
transform(
75407563
Record({ key: encodedBoundSchema(key), value }).annotations({
75417564
description: "a record to be decoded into a ReadonlyMap"
@@ -7555,7 +7578,7 @@ export const ReadonlyMapFromRecord = <KA, KR, VA, VI, VR>({ key, value }: {
75557578
export const MapFromRecord = <KA, KR, VA, VI, VR>({ key, value }: {
75567579
key: Schema<KA, string, KR>
75577580
value: Schema<VA, VI, VR>
7558-
}): Schema<Map<KA, VA>, { readonly [x: string]: VI }, KR | VR> =>
7581+
}): SchemaClass<Map<KA, VA>, { readonly [x: string]: VI }, KR | VR> =>
75597582
transform(
75607583
Record({ key: encodedBoundSchema(key), value }).annotations({
75617584
description: "a record to be decoded into a Map"
@@ -8021,7 +8044,9 @@ export const betweenBigDecimal = <S extends Schema.Any>(
80218044
*/
80228045
export const clampBigDecimal =
80238046
(minimum: bigDecimal_.BigDecimal, maximum: bigDecimal_.BigDecimal) =>
8024-
<A extends bigDecimal_.BigDecimal, I, R>(self: Schema<A, I, R>): transform<Schema<A, I, R>, filter<Schema<A>>> =>
8047+
<S extends Schema.Any, A extends bigDecimal_.BigDecimal>(
8048+
self: S & Schema<A, Schema.Encoded<S>, Schema.Context<S>>
8049+
): transform<S, filter<SchemaClass<A>>> =>
80258050
transform(
80268051
self,
80278052
self.pipe(typeSchema, betweenBigDecimal(minimum, maximum)),

0 commit comments

Comments
 (0)
Please sign in to comment.