import { Ts } from '@wollybeard/kit' import { Mask } from './$.js' import type { InferOptions, Mask as MaskType, PropertiesMask } from './mask.js' // Test 1: InferOptions with unknown should accept all option types { type Options = InferOptions // This is a type-level assertion - we need to use a different pattern type _Test = Ts.AssertEqual> // All of these should be valid options const option1: Options = true const option2: Options = false const option3: Options = [`name`, `age`] const option4: Options = [] const option5: Options = { name: true, age: false } const option6: Options = {} } // Test 2: Mask.create with unknown data type should accept all option types { // Boolean options const mask1 = Mask.create(true) const mask2 = Mask.create(false) // Without explicit type parameter, returns union type Ts.assertEqual>()(mask1) Ts.assertEqual>()(mask2) // Array options (no type parameter needed) const mask3 = Mask.create([`name`, `age`]) const mask4 = Mask.create([]) const mask5 = Mask.create([`a`, `b`, `c`]) // Returns union type with inferred properties Ts.assertEqual>()(mask3) Ts.assertEqual>()(mask4) Ts.assertEqual>()(mask5) // Object options const mask6 = Mask.create({ name: true, age: false }) const mask7 = Mask.create({}) const mask8 = Mask.create({ foo: true, bar: true, baz: false }) // Returns union type with inferred properties Ts.assertEqual>()(mask6) Ts.assertEqual>()(mask7) Ts.assertEqual>()(mask8) } // Test 3: With specific data type, options are constrained { interface User { name: string age: number email: string } // Valid options const mask1 = Mask.create(true) const mask2 = Mask.create([`name`, `age`]) const mask3 = Mask.create({ name: true, age: false, email: true }) // With explicit type parameter, still returns union type Ts.assertEqual>()(mask1) Ts.assertEqual>()(mask2) Ts.assertEqual>()(mask3) // Invalid cases would be compile errors // const mask4 = Mask.create(['invalid']) // Error: 'invalid' is not a key of User // const mask5 = Mask.create({ invalid: true }) // Error: 'invalid' is not a property of User } // Test 4: Non-object types only accept boolean { const mask1 = Mask.create(true) const mask2 = Mask.create(false) Ts.assertEqual>()(mask1) Ts.assertEqual>()(mask2) // Invalid cases would be compile errors // const mask3 = Mask.create(['prop']) // Error: string is not an object // const mask4 = Mask.create({ prop: true }) // Error: string is not an object } // Test 5: Test inference in practical scenarios { // Should infer PropertiesMask with object data type const userMask = Mask.create([`name`, `email`, `password`]) Ts.assertEqual>()(userMask) // When mask is a union type, apply returns a union of possible results const user1 = { name: `John`, email: `john@example.com`, password: `secret`, extra: `data` } const maskedUser1 = Mask.apply(user1, userMask) // Result is a union type that includes the properties mask result type MaskedUser1 = typeof maskedUser1 // Can't use assertSub with union types // For partial data, use applyPartial const user2 = { name: `Jane`, email: `jane@example.com` } const maskedUser2 = Mask.applyPartial(user2, userMask) // Result is a union type type MaskedUser2 = typeof maskedUser2 } // Test 6: Pick and omit helpers { const pick1 = Mask.pick([`name`, `email`]) const omit1 = Mask.omit([`password`, `secret`]) // Infers specific property types Ts.assertEqual>()(pick1) Ts.assertEqual>()(omit1) interface User { name: string email: string password: string } const pick2 = Mask.pick([`name`, `email`]) const omit2 = Mask.omit([`password`]) Ts.assertEqual>()(pick2) Ts.assertEqual>()(omit2) } // Test 7: Apply type transformations { interface User { name: string email: string password: string } const user: User = { name: `John`, email: `john@example.com`, password: `secret` } // Binary mask const showMask = Mask.create(true) const hideMask = Mask.create(false) const shown = Mask.apply(user, showMask) const hidden = Mask.apply(user, hideMask) // showMask and hideMask are MaskType (union types), so results are unions type ShownType = typeof shown // Omit | undefined type HiddenType = typeof hidden // Omit | undefined // Properties mask - allow mode const allowMask = Mask.create([`name`, `email`]) const allowed = Mask.apply(user, allowMask) // Result is a union due to mask being a union type type AllowedType = typeof allowed // Properties mask - deny mode const denyMask = Mask.create({ password: false }) const denied = Mask.apply(user, denyMask) // Result is a union due to mask being a union type type DeniedType = typeof denied }