(tag: Tag)
| 6270 | * @since 4.0.0 |
| 6271 | */ |
| 6272 | export function toTaggedUnion<const Tag extends PropertyKey>(tag: Tag) { |
| 6273 | return <const Members extends ReadonlyArray<Constraint & { readonly Type: { readonly [K in Tag]: PropertyKey } }>>( |
| 6274 | self: Union<Members> |
| 6275 | ): toTaggedUnion<Tag, Members> => { |
| 6276 | const cases: Record<PropertyKey, unknown> = {} |
| 6277 | const discriminants: Array<PropertyKey> = [] |
| 6278 | const discriminantKeys = new Set<string | symbol>() |
| 6279 | const guards: Record<PropertyKey, (u: unknown) => boolean> = {} |
| 6280 | const isAnyOf = (keys: ReadonlyArray<PropertyKey>) => (value: Members[number]["Type"]) => keys.includes(value[tag]) |
| 6281 | |
| 6282 | walk(self) |
| 6283 | |
| 6284 | return Object.assign(self, { cases, discriminants, isAnyOf, guards, match }) as any |
| 6285 | |
| 6286 | function walk(schema: Constraint) { |
| 6287 | const ast = schema.ast |
| 6288 | |
| 6289 | if ( |
| 6290 | SchemaAST.isUnion(ast) && "members" in schema && globalThis.Array.isArray(schema.members) && |
| 6291 | schema.members.every(isSchema) |
| 6292 | ) { |
| 6293 | return schema.members.forEach(walk) |
| 6294 | } |
| 6295 | |
| 6296 | const sentinels = SchemaAST.collectSentinels(ast) |
| 6297 | if (sentinels.length > 0) { |
| 6298 | const literal = sentinels.find((s) => s.key === tag)?.literal |
| 6299 | if (Predicate.isPropertyKey(literal)) { |
| 6300 | const key = typeof literal === "number" ? globalThis.String(literal) : literal |
| 6301 | if (discriminantKeys.has(key)) { |
| 6302 | throw new globalThis.Error(`Duplicate discriminant: ${globalThis.String(literal)}`) |
| 6303 | } |
| 6304 | discriminantKeys.add(key) |
| 6305 | discriminants.push(literal) |
| 6306 | InternalRecord.assignProperty(cases, literal, schema) |
| 6307 | InternalRecord.assignProperty(guards, literal, is(toType(schema))) |
| 6308 | return |
| 6309 | } |
| 6310 | } |
| 6311 | |
| 6312 | throw new globalThis.Error("No literal or unique symbol found") |
| 6313 | } |
| 6314 | |
| 6315 | function match() { |
| 6316 | if (arguments.length === 1) { |
| 6317 | const cases = arguments[0] |
| 6318 | return function(value: any) { |
| 6319 | const key = value[tag] |
| 6320 | const handler = Object.hasOwn(cases, key) ? cases[key] : undefined |
| 6321 | return handler(value) |
| 6322 | } |
| 6323 | } |
| 6324 | const value = arguments[0] |
| 6325 | const cases = arguments[1] |
| 6326 | const key = value[tag] |
| 6327 | const handler = Object.hasOwn(cases, key) ? cases[key] : undefined |
| 6328 | return handler(value) |
| 6329 | } |
no test coverage detected