refactor(question): effectify QuestionService (#17432)

This commit is contained in:
Kit Langton
2026-03-14 11:58:00 -04:00
committed by GitHub
parent 88226f3061
commit cec1255b36
9 changed files with 345 additions and 229 deletions

View File

@@ -15,3 +15,40 @@ export const withStatics =
<S extends object, M extends Record<string, unknown>>(methods: (schema: S) => M) =>
(schema: S): S & M =>
Object.assign(schema, methods(schema))
declare const NewtypeBrand: unique symbol
type NewtypeBrand<Tag extends string> = { readonly [NewtypeBrand]: Tag }
/**
* Nominal wrapper for scalar types. The class itself is a valid schema —
* pass it directly to `Schema.decode`, `Schema.decodeEffect`, etc.
*
* @example
* class QuestionID extends Newtype<QuestionID>()("QuestionID", Schema.String) {
* static make(id: string): QuestionID {
* return this.makeUnsafe(id)
* }
* }
*
* Schema.decodeEffect(QuestionID)(input)
*/
export function Newtype<Self>() {
return <const Tag extends string, S extends Schema.Top>(tag: Tag, schema: S) => {
type Branded = NewtypeBrand<Tag>
abstract class Base {
declare readonly [NewtypeBrand]: Tag
static makeUnsafe(value: Schema.Schema.Type<S>): Self {
return value as unknown as Self
}
}
Object.setPrototypeOf(Base, schema)
return Base as unknown as
& (abstract new (_: never) => Branded)
& { readonly makeUnsafe: (value: Schema.Schema.Type<S>) => Self }
& Omit<Schema.Opaque<Self, S, {}>, "makeUnsafe">
}
}