error.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { Schema } from "effect"
  2. export abstract class NamedError extends Error {
  3. abstract schema(): Schema.Top
  4. abstract toObject(): { name: string; data: unknown }
  5. static hasName(error: unknown, name: string): boolean {
  6. return (
  7. typeof error === "object" && error !== null && "name" in error && (error as Record<string, unknown>).name === name
  8. )
  9. }
  10. static create<Name extends string, Fields extends Schema.Struct.Fields>(
  11. name: Name,
  12. fields: Fields,
  13. ): ReturnType<typeof NamedError.createSchemaClass<Name, Schema.Struct<Fields>>>
  14. static create<Name extends string, DataSchema extends Schema.Top>(
  15. name: Name,
  16. data: DataSchema,
  17. ): ReturnType<typeof NamedError.createSchemaClass<Name, DataSchema>>
  18. static create<Name extends string>(name: Name, data: Schema.Top | Schema.Struct.Fields) {
  19. return NamedError.createSchemaClass(name, Schema.isSchema(data) ? data : Schema.Struct(data))
  20. }
  21. private static createSchemaClass<Name extends string, DataSchema extends Schema.Top>(name: Name, data: DataSchema) {
  22. const schema = Schema.Struct({
  23. name: Schema.Literal(name),
  24. data,
  25. }).annotate({ identifier: name })
  26. type Data = Schema.Schema.Type<DataSchema>
  27. const result = class extends NamedError {
  28. public static readonly Schema = schema
  29. public static readonly EffectSchema = schema
  30. public static readonly tag = name
  31. public override readonly name = name
  32. constructor(
  33. public readonly data: Data,
  34. options?: ErrorOptions,
  35. ) {
  36. super(name, options)
  37. this.name = name
  38. }
  39. static isInstance(input: unknown): input is InstanceType<typeof result> {
  40. return NamedError.hasName(input, name)
  41. }
  42. schema() {
  43. return schema
  44. }
  45. toObject() {
  46. return {
  47. name: name,
  48. data: this.data,
  49. }
  50. }
  51. }
  52. Object.defineProperty(result, "name", { value: name })
  53. return result
  54. }
  55. public static readonly Unknown = NamedError.create("UnknownError", {
  56. message: Schema.String,
  57. ref: Schema.optional(Schema.String),
  58. })
  59. }