@fluidframework/core-interfaces 2.73.0 → 2.74.0-365691
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exposedInternalUtilityTypes.js","sourceRoot":"","sources":["../src/exposedInternalUtilityTypes.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAaH;;GAEG;AACH,MAAM,qBAAqB,GAAkB,MAAM,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @rushstack/no-new-null */\n\nimport type { ErasedType } from \"./erasedType.js\";\nimport type { IFluidHandle } from \"./handles.js\";\nimport type {\n\tSerializationErrorPerNonPublicProperties,\n\tSerializationErrorPerUndefinedArrayElement,\n} from \"./jsonSerializationErrors.js\";\nimport type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from \"./jsonType.js\";\nimport type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from \"./opaqueJson.js\";\n\n/**\n * Unique symbol for recursion meta-typing.\n */\nconst RecursionMarkerSymbol: unique symbol = Symbol(\"recursion here\");\n\n/**\n * Union of types that {@link DeepReadonly} and {@link ShallowReadonly}\n * recognize to generate immutable form and optionally can alter their\n * type parameters.\n *\n * @privateRemarks\n * WeakRef should be added when lib is updated to ES2021 or later.\n *\n * @beta\n */\nexport type ReadonlySupportedGenerics =\n\t| IFluidHandle\n\t| Map<unknown, unknown>\n\t| Promise<unknown>\n\t| Set<unknown>\n\t| WeakMap<object, unknown>\n\t| WeakSet<object>;\n\n/**\n * Limit on processing recursive types.\n * Use of `\"NoLimit\"` may result in error:\n * \"ts(2589): Type instantiation is excessively deep and possibly infinite\".\n * In such cases, use string literal with some prefix series of `+`\n * characters. The length of `+` character sequence indicates the recursion\n * depth limit when a recursive type is found. Use of `0` will stop applying\n * `DeepReadonly` at the first point recursion is detected.\n *\n * @beta\n * @system\n */\nexport type DeepReadonlyRecursionLimit = \"NoLimit\" | 0 | `+${string}`;\n\n/**\n * Collection of utility types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @privateRemarks\n * There are ony three intentional exports from this module:\n * - {@link InternalUtilityTypes.IfSameType | IfSameType}\n * - {@link InternalUtilityTypes.JsonDeserializedImpl | JsonDeserializedImpl }\n * - {@link InternalUtilityTypes.JsonSerializableImpl | JsonSerializableImpl }\n *\n * api-extractor will allow `export` to be removed from others but generates\n * api-report a little oddly with a rogue `{};` floating at end of namespace\n * in api.md file. It will promote all of the support types to appear as\n * exported anyway. All in namespace are left exported to avoid api-extractor\n * potentially failing to validate other modules correctly.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalUtilityTypes {\n\t/**\n\t * Meta-type for controlling filtering utilities.\n\t *\n\t * @system\n\t */\n\texport interface FilterControls {\n\t\t/**\n\t\t * Tuple of exact types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Only exact types matching specification will be preserved unaltered.\n\t\t */\n\t\tAllowExactly: unknown[];\n\n\t\t/**\n\t\t * General types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Any type satisfying specification will be preserved unaltered.\n\t\t */\n\t\tAllowExtensionOf: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling filtering utilities that additionally supplies\n\t * a substitute type for degenerate cases.\n\t *\n\t * @system\n\t */\n\tinterface FilterControlsWithSubstitution extends FilterControls {\n\t\t/**\n\t\t * Type to use for degenerate cases like `unknown` or `any`.\n\t\t * Typically this will be `JsonTypeWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateSubstitute: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling deserialized filtering utilities.\n\t *\n\t * @system\n\t */\n\tinterface DeserializedFilterControls extends FilterControlsWithSubstitution {\n\t\t/**\n\t\t * Type to use for degenerate `object` case.\n\t\t * Typically this will be `NonNullJsonObjectWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateNonNullObjectSubstitute: unknown;\n\n\t\t/**\n\t\t * Either `RecursionMarker` when filtering after recursion has been replace or `never`\n\t\t */\n\t\tRecursionMarkerAllowed: unknown; // Can be RecursionMarker ?\n\t}\n\n\t/**\n\t * Returns non-symbol keys for optional properties of an object type.\n\t * This excludes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as OptionalNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type OptionalNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? never : K;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol keys for required properties of an object type.\n\t * This includes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as RequiredNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type RequiredNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? K : never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns Result.WhenSomethingDeserializable if T is sometimes at least a\n\t * partially deserializable type, otherwise Result.WhenNeverDeserializable.\n\t * Fully not deserializable (bigints, symbols, undefined and functions without\n\t * other properties less overlap with T*Exception) produce Result.WhenNeverDeserializable.\n\t * An object would have a defined result even if parts of its content are\n\t * not deserializable.\n\t *\n\t * @param Result - Result type with two properties. One property must always\n\t * be `never` as `T` maybe a union of never deserializable and at least\n\t * partially deserializable types and the result is a union of Result.*.\n\t *\n\t * @privateRemarks\n\t * If `Result.WhenSomethingDeserializable` was `true` and\n\t * `Result.WhenNeverDeserializable` was `false`, then the return type\n\t * for type `T` would be `boolean` for a sometimes deserializable type.\n\t *\n\t * @system\n\t */\n\texport type TestDeserializabilityOf<\n\t\tT,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tResult extends\n\t\t\t| { WhenSomethingDeserializable: unknown; WhenNeverDeserializable: never }\n\t\t\t| { WhenSomethingDeserializable: never; WhenNeverDeserializable: unknown },\n\t> = /* ensure working with more than never */ T extends never\n\t\t? /* never => */ Result[\"WhenNeverDeserializable\"]\n\t\t: /* check for extends exception */ T extends TExtendsException\n\t\t\t? /* extends exception => */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t: /* no extends exception => check for exact exception */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTExactExceptions,\n\t\t\t\t\t/* exact exception => */ Result[\"WhenSomethingDeserializable\"],\n\t\t\t\t\t/* no exception => check for only non-serializable value types */ T extends\n\t\t\t\t\t\t| bigint\n\t\t\t\t\t\t| symbol\n\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact `U`s from `T`\n\t * rather than any type that extends `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactly<T, U> = IfSameType<T, U, never, T>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact members of `U` from `T`\n\t * rather than any type that extends members of `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactlyInTuple<T, TupleOfU extends unknown[]> = IfExactTypeInTuple<\n\t\tT,\n\t\tTupleOfU,\n\t\tnever,\n\t\tT\n\t>;\n\n\t/**\n\t * Similar to `Omit` but operates on tuples.\n\t * Removes elements of `Tuple` that extend `U`.\n\t *\n\t * @system\n\t */\n\texport type OmitFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitFromTuple<Rest, U, First extends U ? Accumulated : [...Accumulated, First]>\n\t\t: Accumulated;\n\n\t/**\n\t * Similar to `OmitFromTuple` but removes only exact matches of U.\n\t * Removes elements of `Tuple` that are exactly `U`.\n\t *\n\t * @remarks If `U` is a union, then only exactly matching union elements of `Tuple` are removed.\n\t * @system\n\t */\n\texport type OmitExactlyFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitExactlyFromTuple<Rest, U, IfSameType<First, U, Accumulated, [...Accumulated, First]>>\n\t\t: Accumulated;\n\n\t/**\n\t * Returns non-symbol keys for defined, (likely) serializable properties of an\n\t * object type. Literal keys with fully unsupported properties (undefined, symbol,\n\t * and bigint) and sometimes unsupported (functions) are excluded. An exception to\n\t * that is when there are supported types in union with just bigint. Indexed keys\n\t * are only excluded when there are no supported properties.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolWithDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: /* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\tExcludeExactlyInTuple<\n\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t? IfSameType<\n\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t/* value might not be supported => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t>,\n\t\t\t\t\t\t/* extract types that might lead to missing property */ Extract<\n\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t/* types that might lead to missing property, except `bigint` */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t\t? /* all types are supported plus possibly `bigint` => */\n\t\t\t\t\t\t\t\t/* check for only `bigint` remaining */ IfSameType<\n\t\t\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t\t\tbigint,\n\t\t\t\t\t\t\t\t\t/* only `bigint` => nothing supported */ never,\n\t\t\t\t\t\t\t\t\t/* exclusively supported types (and maybe `bigint`) or exactly `never` */\n\t\t\t\t\t\t\t\t\t/* => check for `never` */ T[K] extends never ? never : K\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* value might not be supported => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: /* => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: /* => exclude K */ never;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t: never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol, literal keys for partially supported properties of an object type.\n\t * Keys with only unsupported properties (undefined, symbol, bigint, and\n\t * functions without other properties) are excluded.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithPossiblyDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: IfIndexOrBrandedKey<\n\t\t\t\tK,\n\t\t\t\t/* indexed => exclude K */ never,\n\t\t\t\t/* literal => ... */\n\t\t\t\t/* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\t\tExcludeExactlyInTuple<\n\t\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t\t? Extract<\n\t\t\t\t\t\t\tIfSameType<PossibleTypeLessAllowed, unknown, undefined, PossibleTypeLessAllowed>,\n\t\t\t\t\t\t\t/* types that might lead to missing property */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t? /* exclusively supported types or exactly `never` */ never\n\t\t\t\t\t\t: /* at least some unsupported type => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: K;\n\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: never;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t>;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Filters a type `T` for `undefined` that is not viable in an array (or tuple) that\n\t * must go through JSON serialization.\n\t * If `T` is `undefined`, then error type {@link SerializationErrorPerUndefinedArrayElement}\n\t * is returned with hopes of being informative.\n\t *\n\t * @system\n\t */\n\texport type JsonForSerializableArrayItem<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[],\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined. */\n\t/* These tests are expected to match those in JsonSerializableImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for exact recursion */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t/* recursion; stop here => */ T,\n\t\t\t\t\t/* test for JSON primitive types or given alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t? /* primitive types or alternative => */ T\n\t\t\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* test for undefined possibility */ undefined extends T\n\t\t\t\t\t\t\t\t\t? /* undefined | ... => */ SerializationErrorPerUndefinedArrayElement\n\t\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t\t\t>\n\t\t\t\t>;\n\n\t/**\n\t * Filters a type `T` for types that become null through JSON serialization.\n\t *\n\t * @system\n\t */\n\texport type JsonForDeserializedArrayItem<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined, symbol, or function. */\n\t/* These tests are expected to match those in JsonDeserializedImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for JSON primitive types or general alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive or replaced types => */ T\n\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t/* exactly replaced => */ T,\n\t\t\t\t\t\t/* test for known types that become null */ T extends undefined | symbol\n\t\t\t\t\t\t\t? /* => */ null\n\t\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t: null | TBlessed\n\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t>;\n\n\t/**\n\t * Checks for a type that is simple class of number and string indexed types to numbers and strings.\n\t *\n\t * @system\n\t */\n\texport type IfEnumLike<\n\t\tT extends object,\n\t\tEnumLike = never,\n\t\tNotEnumLike = unknown,\n\t> = T extends readonly (infer _)[]\n\t\t? /* array => */ NotEnumLike\n\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\tT extends Function\n\t\t\t? /* function => */ NotEnumLike\n\t\t\t: T extends {\n\t\t\t\t\t\t// all numerical indices should refer to a string\n\t\t\t\t\t\treadonly [i: number]: string;\n\t\t\t\t\t\t// string indices may be string or number\n\t\t\t\t\t\treadonly [p: string]: number | string;\n\t\t\t\t\t\t// no symbol indices are allowed\n\t\t\t\t\t\treadonly [s: symbol]: never;\n\t\t\t\t\t}\n\t\t\t\t? /* test for a never or any property */ true extends {\n\t\t\t\t\t\t[K in keyof T]: T[K] extends never ? true : never;\n\t\t\t\t\t}[keyof T]\n\t\t\t\t\t? NotEnumLike\n\t\t\t\t\t: EnumLike\n\t\t\t\t: NotEnumLike;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns IfSame if identical and IfDifferent otherwise.\n\t *\n\t * Implementation derived from https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IfSameType<X, Y, IfSame = unknown, IfDifferent = never> = (<T>() => T extends X\n\t\t? 1\n\t\t: 2) extends <T>() => T extends Y ? 1 : 2\n\t\t? IfSame\n\t\t: IfDifferent;\n\n\t/**\n\t * Test for type equality with tuple of other types.\n\t *\n\t * @typeParam T - Type to find in Tuple.\n\t * @typeParam Tuple - Tuple of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @privateRemarks\n\t * Tests for an exact match of `T` in `Tuple[0]`. If not found,\n\t * recurses with the remainder of the tuple.\n\t */\n\texport type IfExactTypeInTuple<\n\t\tT,\n\t\tTuple extends unknown[],\n\t\tIfMatch = unknown,\n\t\tIfNoMatch = never,\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? IfSameType<T, First, IfMatch, IfExactTypeInTuple<T, Rest, IfMatch, IfNoMatch>>\n\t\t: IfNoMatch;\n\n\t/**\n\t * Test for type equality with union of other types.\n\t *\n\t * @typeParam T - Type to find in Union. If this is itself a union, then all types must be found in Union.\n\t * @typeParam Union - Union of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @remarks\n\t * In a recursive context, use {@link InternalUtilityTypes.IfExactTypeInTuple} to manage ancestry.\n\t *\n\t * @privateRemarks\n\t * Perhaps it is a Typescript defect but a simple check that `T` is `never`\n\t * via `T extends never` does not work as expected in this context.\n\t * Workaround using `IfSameType<..., never,...>`.\n\t * @system\n\t */\n\texport type IfExactTypeInUnion<T, Union, IfMatch = unknown, IfNoMatch = never> = IfSameType<\n\t\tT,\n\t\tnever,\n\t\t/* T is never => */ IfSameType<Union, never, IfMatch, IfNoMatch>,\n\t\t/* T is NOT never => */ IfSameType<T, Extract<Union, T>, IfMatch, IfNoMatch>\n\t>;\n\n\t/**\n\t * Check for a template literal that has $\\{string\\} or $\\{number\\}\n\t * in the pattern. Just `string` and/or `number` also match.\n\t *\n\t * @remarks This works recursively looking at first elements when not\n\t * `string` or `number`. `first` will just be a single character if\n\t * not $\\{string\\} or $\\{number\\}.\n\t *\n\t * @system\n\t */\n\texport type IfVariableStringOrNumber<T, IfVariable, IfLiteral> = `${string}` extends T\n\t\t? IfVariable\n\t\t: number extends T\n\t\t\t? IfVariable\n\t\t\t: T extends `${infer first}${infer rest}`\n\t\t\t\t? string extends first\n\t\t\t\t\t? IfVariable\n\t\t\t\t\t: `${number}` extends first\n\t\t\t\t\t\t? IfVariable\n\t\t\t\t\t\t: IfVariableStringOrNumber<rest, IfVariable, IfLiteral>\n\t\t\t\t: IfLiteral;\n\n\t/**\n\t * Essentially a check for a non-fixed number or string OR a branded key.\n\t *\n\t * @remarks There is no known mechanism to determine the primitive from a\n\t * generic tagged (branded) primitive, such as `X$\\{string\\}` & \\{ foo: \"bar\" \\}.\n\t * There appears to be little use for a branded literal key -- at runtime\n\t * there is no brand; so, two of the same literal with different brands would\n\t * collide. Thus any branded key can usually be considered indexed.\n\t *\n\t * @system\n\t */\n\texport type IfIndexOrBrandedKey<\n\t\tT extends keyof AnyRecord,\n\t\tIfIndexOrBranded,\n\t\tOtherwise,\n\t> = T extends object\n\t\t? /* branded string or number */ IfIndexOrBranded\n\t\t: /* => check for variable */ IfVariableStringOrNumber<T, IfIndexOrBranded, Otherwise>;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns `true` if identical and `false` otherwise.\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IsSameType<X, Y> = IfSameType<X, Y, true, false>;\n\n\t/**\n\t * Checks that type is exactly `object`.\n\t *\n\t * @system\n\t */\n\texport type IsExactlyObject<T extends object> = IsSameType<T, object>;\n\n\t/**\n\t * Any Record type.\n\t *\n\t * @system\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- `any` for property types is required to avoid \"Index signature for type 'string' is missing in type\" in some outside `FlattenIntersection` uses.\n\texport type AnyRecord = Record<keyof any, any>;\n\n\t/**\n\t * Creates a simple object type from an intersection of multiple.\n\t * @privateRemarks\n\t * `T extends AnyRecord` within the implementation encourages tsc to process\n\t * intersections within unions.\n\t *\n\t * @system\n\t */\n\texport type FlattenIntersection<T extends AnyRecord> = T extends AnyRecord\n\t\t? {\n\t\t\t\t[K in keyof T]: T[K];\n\t\t\t}\n\t\t: T;\n\n\t/**\n\t * Convenience constraint for any OpaqueJson* type.\n\t *\n\t * @remarks\n\t * Use in extends check: `T extends AnyOpaqueJsonType`\n\t *\n\t * @system\n\t */\n\texport type AnyOpaqueJsonType =\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t\t| OpaqueJsonSerializable<unknown, any, unknown>\n\t\t| OpaqueJsonDeserialized<unknown, any, unknown>;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Extracts Function portion from an intersection (&) type returning\n\t * the extracted portion in the `function` property or `unknown` if\n\t * no function is found.\n\t * The returned `classification` property has one of three values:\n\t * - \"no Function\" if the type is not a function.\n\t * - \"exactly Function\" if the type is exactly a function.\n\t * - \"Function and more\" if the type is a function and has other properties.\n\t *\n\t * @system\n\t */\n\texport type ExtractFunctionFromIntersection<T extends object> = (T extends new (\n\t\t...args: infer A\n\t) => infer R\n\t\t? new (\n\t\t\t\t...args: A\n\t\t\t) => R\n\t\t: unknown) &\n\t\t(T extends (...args: infer A) => infer R\n\t\t\t? (...args: A) => R\n\t\t\t: unknown) extends infer Functional\n\t\t? {\n\t\t\t\tclassification: unknown extends Functional\n\t\t\t\t\t? \"no Function\"\n\t\t\t\t\t: Functional extends Required<T>\n\t\t\t\t\t\t? \"exactly Function\"\n\t\t\t\t\t\t: \"Function and more\";\n\t\t\t\tfunction: Functional;\n\t\t\t}\n\t\t: never;\n\n\t/**\n\t * Returns `Filtered` & any Function intersection from `Original`.\n\t * If `Original` is exactly a Function, then `Filtered` is left out\n\t * under the assumption that it is not useful/applicable.\n\t *\n\t * @system\n\t */\n\texport type FilterPreservingFunction<\n\t\tOriginal extends object,\n\t\tFiltered,\n\t> = ExtractFunctionFromIntersection<Original> extends {\n\t\tclassification: infer TClassification;\n\t\tfunction: infer TFunction;\n\t}\n\t\t? TClassification extends \"exactly Function\"\n\t\t\t? TFunction\n\t\t\t: TFunction & Filtered\n\t\t: never;\n\n\t/**\n\t * Replaces any instance where a type T recurses into itself or a portion of\n\t * itself with TRecursionMarker.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam TRecursionMarker - Replacement marker type.\n\t * @typeParam Controls - Allowances are preserved as-is.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @remarks\n\t * Filtering applied to class instances with non-public properties will not\n\t * preserve the class instance unless those classes are known and listed as\n\t * allowances via `Controls`.\n\t *\n\t * @privateRemarks\n\t * This implementation handles functions including function with properties.\n\t * There are no known cases where replacing recursion under such types make\n\t * a difference. Either the function (whole type) is allowed by the Json\n\t * filters or function is not allowed at all.\n\t * If the function portion is found to be problematic later, then could use\n\t * `T extends Function ? T : ...` to ignore function objects.\n\t *\n\t * @system\n\t */\n\texport type ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tTRecursionMarker,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for recursion */\n\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion => use replacement */ TRecursionMarker\n\t\t: /* force union separation hereafter */ T extends infer _\n\t\t\t? /* test for recursion among union elements */\n\t\t\t\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? TRecursionMarker\n\t\t\t\t: /* test for general allowance */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* allowed extension type => */ T\n\t\t\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact allowed type => */ T\n\t\t\t\t\t\t: T extends object\n\t\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tTRecursionMarker,\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* non-object => T as is */ T\n\t\t\t: never;\n\n\t/**\n\t * Replaces any instances of \"allowed\" types and recursion within with `never`.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam Controls - Allowances to replace.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @system\n\t */\n\texport type ReplaceAllowancesAndRecursionWithNever<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for exact recursion first */ IfExactTypeInTuple<\n\t\tT,\n\t\tTAncestorTypes,\n\t\ttrue,\n\t\t\"no match\"\n\t> extends true\n\t\t? /* recursion => */ never\n\t\t: /* test for general allowance (also forces union separation) */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t? /* allowed extension type => */ never\n\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact allowed type => */ never\n\t\t\t\t: /* test for recursion among union elements */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* recursion => */ never\n\t\t\t\t\t: T extends object\n\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceAllowancesAndRecursionWithNever<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* non-object => T as is */ T;\n\n\t/**\n\t * Test for non-public properties (which can only exist on class instance types).\n\t *\n\t * Returns `HasNonPublic` if `T` deeply may contain a private or protected field\n\t * and `OnlyPublics` otherwise.\n\t *\n\t * @remarks\n\t * Compare original (unprocessed) to filtered case that has `never` where\n\t * recursing or where allowed exception types are used.\n\t *\n\t * Note that this a test of the type and not the actual data. So, if an\n\t * interface is given as `T` where implemented by a class, any private or\n\t * protected fields within the class will not be detected.\n\t *\n\t * @system\n\t */\n\texport type IfNonPublicProperties<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tHasNonPublic = never,\n\t\tOnlyPublics = unknown,\n\t> = ReplaceAllowancesAndRecursionWithNever<T, Controls> extends T\n\t\t? OnlyPublics\n\t\t: HasNonPublic;\n\n\t/**\n\t * Union of all types in a tuple.\n\t *\n\t * @system\n\t */\n\texport type TupleToUnion<T extends unknown[]> = T[number];\n\n\t// #region JsonSerializable implementation\n\n\t/**\n\t * Outer implementation of {@link JsonSerializable} handling meta cases\n\t * like classes (with non-public properties).\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls> & {\n\t\t\t/**\n\t\t\t * See {@link JsonSerializableOptions} for meaning and expected use.\n\t\t\t */\n\t\t\tIgnoreInaccessibleMembers?: \"ignore-inaccessible-members\";\n\t\t},\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute type could be extracted to helper type, but is kept explicit here\n\t\t// to make JsonTypeWith and OpaqueJsonSerializable show explicitly in results for\n\t\t// users, rather than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute:\n\t\t\t| JsonTypeWith<\n\t\t\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t\t\t: never)\n\t\t\t\t\t| (Options extends { AllowExtensionOf: unknown }\n\t\t\t\t\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t: never)\n\t\t\t >\n\t\t\t| OpaqueJsonSerializable<\n\t\t\t\t\tunknown,\n\t\t\t\t\tOptions extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [],\n\t\t\t\t\tOptions extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never\n\t\t\t >;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy FilterControlsWithSubstitution, but Typescript wants a check */\n\t\t\tControls extends FilterControlsWithSubstitution\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: Options extends { IgnoreInaccessibleMembers: \"ignore-inaccessible-members\" }\n\t\t\t\t\t? JsonSerializableFilter<T, Controls, TAncestorTypes, TNextAncestor>\n\t\t\t\t\t: /* test for non-public properties (class instance type) */\n\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in primitives that may be branded to ignore intersection classes\n\t\t\t\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t? /* hidden props => test if it is array properties that are the problem */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonSerializableImpl<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: /* test for potentially branded primitive (intersection with a supported primitive) */\n\t\t\t\t\t\t\t\tT extends boolean | number | string\n\t\t\t\t\t\t\t\t? /* assume intersection is branding and allow as-is => */ T\n\t\t\t\t\t\t\t\t: /* not array => error */ SerializationErrorPerNonPublicProperties\n\t\t\t\t\t\t: /* no hidden properties => apply filtering => */ JsonSerializableFilter<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\tTNextAncestor\n\t\t\t\t\t\t\t>\n\t\t\t: never /* FilterControlsWithSubstitution assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonSerializable}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} and {@link OpaqueJsonDeserialized} instances\n\t * are limited to `Controls` given context supports.\n\t * `T` from the original Opaque type is preserved. In the case that this now\n\t * produces an improper type such as a `bigint` being let through that is no\n\t * longer supported, then the variance of `Controls` is expected to raise\n\t * the incompatibility error.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableOpaqueAllowances<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControlsWithSubstitution,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t/* infer underlying data type */ T extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? T extends OpaqueJsonSerializable<TData, any, unknown> &\n\t\t\t\tOpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]> &\n\t\t\t\t\tOpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t: T extends OpaqueJsonSerializable<TData, any, unknown>\n\t\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t\t: T extends OpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t\t\t? OpaqueJsonDeserialized<\n\t\t\t\t\t\t\tTData,\n\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t>\n\t\t\t\t\t: \"internal error: failed to determine OpaqueJson* type\"\n\t\t: never;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Helper for {@link JsonSerializableFilter} to determine if a property may\n\t * be `undefined` and selects from options for result.\n\t * Since `unknown` is a superset of `undefined`, it is given a special case.\n\t * Additionally since index signatures are inherently optional, `unknown` typed\n\t * values are treated as not undefined (`Result[\"Otherwise\"]`).\n\t *\n\t * @system\n\t */\n\texport type IfPossiblyUndefinedProperty<\n\t\tTKey extends keyof AnyRecord,\n\t\tTValue,\n\t\tResult extends {\n\t\t\tIfPossiblyUndefined: unknown;\n\t\t\tIfUnknownNonIndexed: unknown;\n\t\t\tOtherwise: unknown;\n\t\t},\n\t> = undefined extends TValue\n\t\t? unknown extends TValue\n\t\t\t? IfIndexOrBrandedKey<TKey, Result[\"Otherwise\"], Result[\"IfUnknownNonIndexed\"]>\n\t\t\t: Result[\"IfPossiblyUndefined\"]\n\t\t: Result[\"Otherwise\"];\n\n\t/**\n\t * Core implementation of {@link JsonSerializable}.\n\t *\n\t * @privateRemarks\n\t * Filtering through a single layer of recursion is all that is required\n\t * when using in prescribed filter scenario.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableFilter<\n\t\tT,\n\t\tControls extends FilterControlsWithSubstitution,\n\t\tTAncestorTypes extends unknown[],\n\t\tTNextAncestor = T,\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for recursion */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact recursion; stop here => */ T\n\t\t\t\t: /* test for JSON Encodable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t\t| null\n\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t\t: /* test for exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\t/* test for not a function */ Extract<T, Function> extends never\n\t\t\t\t\t\t\t? /* not a function => test for object */ T extends object\n\t\t\t\t\t\t\t\t? /* object => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForSerializableArrayItem<\n\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\t\t\t\t\tJsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t\t? /* `object` => */ NonNullJsonObjectWith<\n\t\t\t\t\t\t\t\t\t\t\t\tTupleToUnion<Controls[\"AllowExactly\"]> | Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t\t: /* test for OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonSerializableOpaqueAllowances<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* required properties are recursed and may not have undefined values. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as RequiredNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]-?: IfPossiblyUndefinedProperty<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfPossiblyUndefined: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `undefined` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfUnknownNonIndexed: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `unknown` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tOtherwise: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* optional properties are recursed and, when exactOptionalPropertyTypes is\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t false, are allowed to preserve undefined value type. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as OptionalNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* symbol properties are rejected */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T & symbol]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t: /* not an object => */ never\n\t\t\t\t\t\t\t: /* function => */ never;\n\n\t// #endregion\n\n\t/**\n\t * Sentinel type for use when marking points of recursion (in a recursive type).\n\t * Type is expected to be unique, though no lengths are taken to ensure that.\n\t *\n\t * @system\n\t */\n\texport interface RecursionMarker {\n\t\t[RecursionMarkerSymbol]: typeof RecursionMarkerSymbol;\n\t}\n\n\t// #region JsonDeserialized implementation\n\n\t/**\n\t * Outer implementation of {@link JsonDeserialized} handling meta cases\n\t * like recursive types.\n\t *\n\t * @remarks\n\t * If no modification is needed (`T` is exactly deserializable), `T` will\n\t * be the result.\n\t *\n\t * Upon recursion with `T` that requires modification, `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing.\n\t * Caller will need to unwrap the type to continue processing.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls>,\n\t\tTypeUnderRecursion extends boolean = false,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute types could be extracted to helper type, but are kept explicit here\n\t\t// to make JsonTypeWith/NonNullJsonObjectWith show explicitly in results for users, rather\n\t\t// than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute: JsonTypeWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tDegenerateNonNullObjectSubstitute: NonNullJsonObjectWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tRecursionMarkerAllowed: never;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy DeserializedFilterControls, but Typescript wants a check */\n\t\t\tControls extends DeserializedFilterControls\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tRecursionMarker,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t// Also preserve OpaqueJson* types\n\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t> extends infer TNoRecursionAndOnlyPublics\n\t\t\t\t\t? /* test for no change from filtered type */ IsSameType<\n\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\tJsonDeserializedFilter<\n\t\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf: Controls[\"AllowExtensionOf\"];\n\t\t\t\t\t\t\t\t\tDegenerateSubstitute: Controls[\"DegenerateSubstitute\"];\n\t\t\t\t\t\t\t\t\tDegenerateNonNullObjectSubstitute: Controls[\"DegenerateNonNullObjectSubstitute\"];\n\t\t\t\t\t\t\t\t\tRecursionMarkerAllowed: RecursionMarker;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* same (no filtering needed) => test for non-public\n\t\t\t\t\t\t properties (class instance type) */\n\t\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t\t\t\t// primitives as JsonDeserializedFilter will allow them as\n\t\t\t\t\t\t\t\t// extensions of the primitives. Should there be a need to\n\t\t\t\t\t\t\t\t// explicitly allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t\t? /* hidden props => apply filtering to avoid retaining\n\t\t\t\t\t\t\t exact class except for any classes in allowances =>\n\t\t\t\t\t\t\t\t test for known recursion */\n\t\t\t\t\t\t\t\tTypeUnderRecursion extends false\n\t\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* no hidden properties => deserialized T is just T */\n\t\t\t\t\t\t\t\tT\n\t\t\t\t\t\t: /* filtering is needed => test for known recursion */ TypeUnderRecursion extends false\n\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t: /* unreachable else for infer */ never\n\t\t\t: never /* DeserializedFilterControls assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.JsonDeserializedFilter} up until\n\t * `T` is found to be a match of an ancestor type. At that point `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing, if\n\t * modification is needed. Caller will need to unwrap the type to continue processing.\n\t * If no modification is needed, then `T` will be the result.\n\t *\n\t * @privateRemarks Exact recursion pattern employed should allow shortcut\n\t * test to return `OpaqueJsonDeserialized<T>` from here when the exact\n\t * recursion match is the first ancestor type in tuple as it must have been\n\t * processed and found to need modification.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedRecursion<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTAncestorTypes extends object[],\n\t> = IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion found => reprocess that recursive type directly to avoid\n\t\t any collateral damage from ancestor type that required modification.\n\t\t\t Further recursion will not happen during processing. Either:\n\t\t\t - the type requires modification and the `TypeUnderRecursion=true`\n\t\t\t arg will result in `OpaqueJsonDeserialized<T>` wrapper OR\n\t\t\t - no change is needed from this point and `T` will result. */\n\t\t\tJsonDeserializedImpl<T, Controls, true>\n\t\t: T extends object\n\t\t\t? IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? JsonDeserializedImpl<T, Controls, true>\n\t\t\t\t: /* no recursion yet detected => */ JsonDeserializedFilter<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls,\n\t\t\t\t\t\t[...TAncestorTypes, T]\n\t\t\t\t\t>\n\t\t\t: /* not an object (no recursion) => */ JsonDeserializedFilter<\n\t\t\t\t\tT,\n\t\t\t\t\tControls,\n\t\t\t\t\tTAncestorTypes\n\t\t\t\t>;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonDeserialized}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} instances are converted to {@link OpaqueJsonDeserialized}.\n\t * The `AllowExactly` and `AllowExtensionOf` properties are set to match the given `Controls`.\n\t * The data type is kept exactly as-is to avoid processing in generic contexts that can't\n\t * produce a meaningful result. The data type should always be filtered through\n\t * {@link JsonDeserialized} when {@link OpaqueJsonDeserialized} is cracked open. So, really\n\t * the filtering is just deferred.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedOpaqueConversion<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControls,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\tT extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? OpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t: \"internal error: failed to determine OpaqueJson* type\";\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Core implementation of {@link JsonDeserialized}.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedFilter<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\t// Always start with object portion of self as ancestor. Filtering will\n\t\t// not apply past recursion (nested occurrence of this).\n\t\tTAncestorTypes extends object[] = [Extract<T, object>],\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for deserializable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t: /* test for given exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"not found\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t: /* test for object */ T extends object\n\t\t\t\t\t\t? /* object => */ ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t? /* exactly function => */ never\n\t\t\t\t\t\t\t: /* not exactly a function (Function portion, if any, is omitted) */\n\t\t\t\t\t\t\t\t/* => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForDeserializedArrayItem<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\tJsonDeserializedRecursion<T[K], Controls, TAncestorTypes>\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t? /* `object` => */ Controls[\"DegenerateNonNullObjectSubstitute\"]\n\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t: /* test for matching OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonDeserializedOpaqueConversion<T, Controls>\n\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with symbol keys or wholly unsupported values are removed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with defined values are recursed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolWithDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* literal properties that may have undefined values are optional */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* not an object => */ never;\n\n\t// #endregion\n\n\t// #region *Readonly implementations\n\n\t/**\n\t * Recursion limit is the count of `+` that prefix it when string.\n\t *\n\t * @system\n\t */\n\texport type RecursionLimit = `+${string}` | 0;\n\n\t/**\n\t * If `T` is a `Map<K,V>` or `ReadonlyMap<K,V>`, returns `ReadonlyMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlyMap<infer K, infer V>\n\t\t? Map<K, V> extends DeepenedGenerics\n\t\t\t? ReadonlyMap<\n\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t>\n\t\t\t: ReadonlyMap<K, V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Set<TSet>` or `ReadonlySet<TSet>`, returns `ReadonlySet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlySet<infer V>\n\t\t? Set<V> extends DeepenedGenerics\n\t\t\t? ReadonlySet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: ReadonlySet<V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `IFluidHandle<THandle>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `THandle` generic.\n\t * `Else` is returned if not an `IFluidHandle`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInFluidHandleIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Readonly<IFluidHandle<infer V>>\n\t\t? IFluidHandle<V> extends DeepenedGenerics\n\t\t\t? Readonly<IFluidHandle<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>>\n\t\t\t: Readonly<T>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Promise<TPromise>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `TPromise` generic.\n\t * `Else` is returned if not a `Promise`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInPromiseIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Promise<infer V>\n\t\t? Promise<V> extends DeepenedGenerics\n\t\t\t? Promise<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: T\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakMap<K,V>`, returns immutable `WeakMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakMap<infer K, infer V>, \"delete\" | \"set\">\n\t\t? WeakMap<K, V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakMap<\n\t\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t\t>,\n\t\t\t\t\t\"delete\" | \"set\"\n\t\t\t\t>\n\t\t\t: Omit<WeakMap<K, V>, \"delete\" | \"set\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakSet<TSet>`, returns immutable `WeakSet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic weak set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakSet<infer V>, \"add\" | \"delete\">\n\t\t? WeakSet<V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakSet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>,\n\t\t\t\t\t\"add\" | \"delete\"\n\t\t\t\t>\n\t\t\t: Omit<WeakSet<V>, \"add\" | \"delete\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a {@link ReadonlySupportedGenerics}, `T` is returned as\n\t * its immutable version, and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `T`s generics.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInGenerics<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics,\n\t\tNoDepthOrRecurseLimit,\n\t\tDeepenReadonlyInSetIfEnabled<\n\t\t\tT,\n\t\t\tDeepenedGenerics,\n\t\t\tNoDepthOrRecurseLimit,\n\t\t\tDeepenReadonlyInWeakMapIfEnabled<\n\t\t\t\tT,\n\t\t\t\tDeepenedGenerics,\n\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\tDeepenReadonlyInWeakSetIfEnabled<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\tDeepenReadonlyInPromiseIfEnabled<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\tDeepenReadonlyInFluidHandleIfEnabled<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\t\tElse\n\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t>\n\t>;\n\n\t/**\n\t * Returns an `ErasedType` or \"branded\" primitive type as-is, or `Else` if not.\n\t * @typeParam T - Type to test.\n\t * @typeParam Else - Type to return if not `ErasedType` or \"branded\" primitive.\n\t *\n\t * @system\n\t */\n\texport type PreserveErasedTypeOrBrandedPrimitive<\n\t\tT extends object,\n\t\tElse,\n\t> = /* Test for erased type */ T extends ErasedType<infer _>\n\t\t? /* erased type => keep as-is */ T\n\t\t: /* Test for branded primitive */ T extends infer Brand &\n\t\t\t\t\t(boolean | number | string | symbol | bigint)\n\t\t\t? // Should just return T here, but TypeScript appears to produce `never` when doing so.\n\t\t\t\t// Workaround by inferring the Primitive type and returning intersection with B.\n\t\t\t\tT extends Brand & infer Primitive\n\t\t\t\t? /* [potentially] branded type => \"as-is\" */ Primitive & Brand\n\t\t\t\t: /* Should never be reached */ T\n\t\t\t: Else;\n\n\t/**\n\t * De-multiplexing implementation of {@link DeepReadonly} and {@link ShallowReadonly}\n\t * selecting behavior based on `NoDepthOrRecurseLimit`.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant. Its importance is that other utilities common to\n\t * readonly transformation may use `NoDepthOrRecurseLimit` to return the the\n\t * same processing algorithm.\n\t *\n\t * @system\n\t */\n\texport type ReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t> = /* test for no depth */ NoDepthOrRecurseLimit extends \"Shallow\"\n\t\t? /* no depth => */ ShallowReadonlyImpl<T, DeepenedGenerics>\n\t\t: /* test for no limit */ NoDepthOrRecurseLimit extends \"NoLimit\"\n\t\t\t? /* no limit => */ DeepReadonlyRecursingInfinitely<T, DeepenedGenerics>\n\t\t\t: /* limited */ DeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>;\n\n\t// #region ShallowReadonly implementation\n\n\t/**\n\t * Outer implementation of {@link ShallowReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility can be reentrant when generics are deepened.\n\t *\n\t * @system\n\t */\n\texport type ShallowReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\"Shallow\",\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<T, /* basic type => */ Readonly<T>>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\n\t/**\n\t * Outer implementation of {@link DeepReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `RecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends DeepReadonlyRecursionLimit,\n\t> = ReadonlyImpl<T, DeepenedGenerics, RecurseLimit>;\n\n\t// #region DeepReadonly infinite recursion implementation\n\n\t/**\n\t * Simple implementation of {@link DeepReadonly} that may handle limited recursive types.\n\t * In unhandled cases, TypeScript will produce:\n\t * ts(2589): Type instantiation is excessively deep and possibly infinite.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursingInfinitely<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\t// test for array of known recursive type: JsonTypeWith\n\t\t\t\tT extends readonly ReadonlyJsonTypeWith<infer Alternates>[]\n\t\t\t\t\t? // Make sure this is exactly that case (many arrays will extend JsonTypeWith)\n\t\t\t\t\t\t// Note that `true extends IfExactTypeInTuple` is used over\n\t\t\t\t\t\t// if-else form as the else branch would be evaluated as input to\n\t\t\t\t\t\t// `IfExactTypeInTuple` and that could lead to infinite recursion.\n\t\t\t\t\t\ttrue extends IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[JsonTypeWith<Alternates>[], readonly ReadonlyJsonTypeWith<Alternates>[]]\n\t\t\t\t\t\t>\n\t\t\t\t\t\t? readonly ReadonlyJsonTypeWith<\n\t\t\t\t\t\t\t\tDeepReadonlyRecursingInfinitely<Alternates, DeepenedGenerics>\n\t\t\t\t\t\t\t>[]\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: /* not JSON array => */ DeepenReadonlyInGenerics<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\"NoLimit\",\n\t\t\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #region DeepReadonly limited recursion implementation\n\n\t/**\n\t * Core implementation of {@link DeepReadonly} handling meta cases\n\t * like recursive types a limited number of times.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `NoDepthOrRecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyLimitingRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends RecursionLimit,\n\t> = /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tRecursionMarker,\n\t\t{ AllowExactly: []; AllowExtensionOf: never }\n\t> extends infer TNoRecursionAndOnlyPublics\n\t\t? /* test for no change from altered type (excluding non-publics) */ IsSameType<\n\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\tDeepReadonlyWorker<TNoRecursionAndOnlyPublics, DeepenedGenerics, 0>\n\t\t\t> extends true\n\t\t\t? /* same (no filtering needed) => test for non-public properties (class instance type) */\n\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\tT,\n\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t// primitives as DeepReadonlyWorker will allow them as\n\t\t\t\t\t// extensions of the primitives. Should there need a need to\n\t\t\t\t\t// explicit allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t{ AllowExactly: []; AllowExtensionOf: never },\n\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\"only publics\"\n\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t? /* hidden props => apply filtering => */\n\t\t\t\t\tDeepReadonlyWorker<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t\t>\n\t\t\t\t: /* no hidden properties => readonly T is just T */\n\t\t\t\t\tT\n\t\t\t: /* filtering is needed => */ DeepReadonlyWorker<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>\n\t\t: /* unreachable else for infer */ never;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.DeepReadonlyWorker} up to `RecurseLimit` times.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = T extends TAncestorTypes\n\t\t? RecurseLimit extends `+${infer RecursionRemainder}`\n\t\t\t? /* Now that specific recursion is found, process that recursive type\n\t\t\t directly to avoid any collateral damage from ancestor type that\n\t\t\t required modification. */\n\t\t\t\tDeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecursionRemainder extends RecursionLimit ? RecursionRemainder : 0\n\t\t\t\t>\n\t\t\t: T\n\t\t: DeepReadonlyWorker<T, DeepenedGenerics, RecurseLimit, TAncestorTypes | T>;\n\n\t/**\n\t * Core implementation of {@link InternalUtilityTypes.DeepReadonlyLimitingRecursion}.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyWorker<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = /* test for object */ T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecurseLimit,\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursion<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\tRecurseLimit,\n\t\t\t\t\t\t\t\tTAncestorTypes\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #endregion\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exposedInternalUtilityTypes.js","sourceRoot":"","sources":["../src/exposedInternalUtilityTypes.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAaH;;GAEG;AACH,MAAM,qBAAqB,GAAkB,MAAM,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @rushstack/no-new-null */\n\nimport type { ErasedType } from \"./erasedType.js\";\nimport type { IFluidHandle } from \"./handles.js\";\nimport type {\n\tSerializationErrorPerNonPublicProperties,\n\tSerializationErrorPerUndefinedArrayElement,\n} from \"./jsonSerializationErrors.js\";\nimport type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from \"./jsonType.js\";\nimport type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from \"./opaqueJson.js\";\n\n/**\n * Unique symbol for recursion meta-typing.\n */\nconst RecursionMarkerSymbol: unique symbol = Symbol(\"recursion here\");\n\n/**\n * Union of types that {@link DeepReadonly} and {@link ShallowReadonly}\n * recognize to generate immutable form and optionally can alter their\n * type parameters.\n *\n * @privateRemarks\n * WeakRef should be added when lib is updated to ES2021 or later.\n *\n * @beta\n */\nexport type ReadonlySupportedGenerics =\n\t| IFluidHandle\n\t| Map<unknown, unknown>\n\t| Promise<unknown>\n\t| Set<unknown>\n\t| WeakMap<object, unknown>\n\t| WeakSet<object>;\n\n/**\n * Limit on processing recursive types.\n * Use of `\"NoLimit\"` may result in error:\n * \"ts(2589): Type instantiation is excessively deep and possibly infinite\".\n * In such cases, use string literal with some prefix series of `+`\n * characters. The length of `+` character sequence indicates the recursion\n * depth limit when a recursive type is found. Use of `0` will stop applying\n * `DeepReadonly` at the first point recursion is detected.\n *\n * @beta\n * @system\n */\nexport type DeepReadonlyRecursionLimit = \"NoLimit\" | 0 | `+${string}`;\n\n/**\n * Collection of utility types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @privateRemarks\n * There are ony three intentional exports from this module:\n * - {@link InternalUtilityTypes.IfSameType | IfSameType}\n * - {@link InternalUtilityTypes.JsonDeserializedImpl | JsonDeserializedImpl }\n * - {@link InternalUtilityTypes.JsonSerializableImpl | JsonSerializableImpl }\n *\n * api-extractor will allow `export` to be removed from others but generates\n * api-report a little oddly with a rogue `{};` floating at end of namespace\n * in api.md file. It will promote all of the support types to appear as\n * exported anyway. All in namespace are left exported to avoid api-extractor\n * potentially failing to validate other modules correctly.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalUtilityTypes {\n\t/**\n\t * Meta-type for controlling filtering utilities.\n\t *\n\t * @system\n\t */\n\texport interface FilterControls {\n\t\t/**\n\t\t * Tuple of exact types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Only exact types matching specification will be preserved unaltered.\n\t\t */\n\t\tAllowExactly: unknown[];\n\n\t\t/**\n\t\t * General types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Any type satisfying specification will be preserved unaltered.\n\t\t */\n\t\tAllowExtensionOf: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling filtering utilities that additionally supplies\n\t * a substitute type for degenerate cases.\n\t *\n\t * @system\n\t */\n\tinterface FilterControlsWithSubstitution extends FilterControls {\n\t\t/**\n\t\t * Type to use for degenerate cases like `unknown` or `any`.\n\t\t * Typically this will be `JsonTypeWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateSubstitute: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling deserialized filtering utilities.\n\t *\n\t * @system\n\t */\n\tinterface DeserializedFilterControls extends FilterControlsWithSubstitution {\n\t\t/**\n\t\t * Type to use for degenerate `object` case.\n\t\t * Typically this will be `NonNullJsonObjectWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateNonNullObjectSubstitute: unknown;\n\n\t\t/**\n\t\t * Either `RecursionMarker` when filtering after recursion has been replace or `never`\n\t\t */\n\t\tRecursionMarkerAllowed: unknown; // Can be RecursionMarker ?\n\t}\n\n\t/**\n\t * Returns non-symbol keys for optional properties of an object type.\n\t * This excludes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as OptionalNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type OptionalNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? never : K;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol keys for required properties of an object type.\n\t * This includes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as RequiredNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type RequiredNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? K : never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns Result.WhenSomethingDeserializable if T is sometimes at least a\n\t * partially deserializable type, otherwise Result.WhenNeverDeserializable.\n\t * Fully not deserializable (bigints, symbols, undefined and functions without\n\t * other properties less overlap with T*Exception) produce Result.WhenNeverDeserializable.\n\t * An object would have a defined result even if parts of its content are\n\t * not deserializable.\n\t *\n\t * @param Result - Result type with two properties. One property must always\n\t * be `never` as `T` maybe a union of never deserializable and at least\n\t * partially deserializable types and the result is a union of Result.*.\n\t *\n\t * @privateRemarks\n\t * If `Result.WhenSomethingDeserializable` was `true` and\n\t * `Result.WhenNeverDeserializable` was `false`, then the return type\n\t * for type `T` would be `boolean` for a sometimes deserializable type.\n\t *\n\t * @system\n\t */\n\texport type TestDeserializabilityOf<\n\t\tT,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tResult extends\n\t\t\t| { WhenSomethingDeserializable: unknown; WhenNeverDeserializable: never }\n\t\t\t| { WhenSomethingDeserializable: never; WhenNeverDeserializable: unknown },\n\t> = /* ensure working with more than never */ T extends never\n\t\t? /* never => */ Result[\"WhenNeverDeserializable\"]\n\t\t: /* check for extends exception */ T extends TExtendsException\n\t\t\t? /* extends exception => */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t: /* no extends exception => check for exact exception */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTExactExceptions,\n\t\t\t\t\t/* exact exception => */ Result[\"WhenSomethingDeserializable\"],\n\t\t\t\t\t/* no exception => check for only non-serializable value types */ T extends\n\t\t\t\t\t\t| bigint\n\t\t\t\t\t\t| symbol\n\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact `U`s from `T`\n\t * rather than any type that extends `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactly<T, U> = IfSameType<T, U, never, T>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact members of `U` from `T`\n\t * rather than any type that extends members of `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactlyInTuple<T, TupleOfU extends unknown[]> = IfExactTypeInTuple<\n\t\tT,\n\t\tTupleOfU,\n\t\tnever,\n\t\tT\n\t>;\n\n\t/**\n\t * Similar to `Omit` but operates on tuples.\n\t * Removes elements of `Tuple` that extend `U`.\n\t *\n\t * @system\n\t */\n\texport type OmitFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitFromTuple<Rest, U, First extends U ? Accumulated : [...Accumulated, First]>\n\t\t: Accumulated;\n\n\t/**\n\t * Similar to `OmitFromTuple` but removes only exact matches of U.\n\t * Removes elements of `Tuple` that are exactly `U`.\n\t *\n\t * @remarks If `U` is a union, then only exactly matching union elements of `Tuple` are removed.\n\t * @system\n\t */\n\texport type OmitExactlyFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitExactlyFromTuple<Rest, U, IfSameType<First, U, Accumulated, [...Accumulated, First]>>\n\t\t: Accumulated;\n\n\t/**\n\t * Returns non-symbol keys for defined, (likely) serializable properties of an\n\t * object type. Literal keys with fully unsupported properties (undefined, symbol,\n\t * and bigint) and sometimes unsupported (functions) are excluded. An exception to\n\t * that is when there are supported types in union with just bigint. Indexed keys\n\t * are only excluded when there are no supported properties.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolWithDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: /* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\tExcludeExactlyInTuple<\n\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t? IfSameType<\n\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t/* value might not be supported => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t>,\n\t\t\t\t\t\t/* extract types that might lead to missing property */ Extract<\n\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t/* types that might lead to missing property, except `bigint` */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t\t? /* all types are supported plus possibly `bigint` => */\n\t\t\t\t\t\t\t\t/* check for only `bigint` remaining */ IfSameType<\n\t\t\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t\t\tbigint,\n\t\t\t\t\t\t\t\t\t/* only `bigint` => nothing supported */ never,\n\t\t\t\t\t\t\t\t\t/* exclusively supported types (and maybe `bigint`) or exactly `never` */\n\t\t\t\t\t\t\t\t\t/* => check for `never` */ T[K] extends never ? never : K\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* value might not be supported => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: /* => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: /* => exclude K */ never;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t: never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol, literal keys for partially supported properties of an object type.\n\t * Keys with only unsupported properties (undefined, symbol, bigint, and\n\t * functions without other properties) are excluded.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithPossiblyDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: IfIndexOrBrandedKey<\n\t\t\t\tK,\n\t\t\t\t/* indexed => exclude K */ never,\n\t\t\t\t/* literal => ... */\n\t\t\t\t/* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\t\tExcludeExactlyInTuple<\n\t\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t\t? Extract<\n\t\t\t\t\t\t\tIfSameType<PossibleTypeLessAllowed, unknown, undefined, PossibleTypeLessAllowed>,\n\t\t\t\t\t\t\t/* types that might lead to missing property */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t? /* exclusively supported types or exactly `never` */ never\n\t\t\t\t\t\t: /* at least some unsupported type => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: K;\n\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: never;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t>;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Filters a type `T` for `undefined` that is not viable in an array (or tuple) that\n\t * must go through JSON serialization.\n\t * If `T` is `undefined`, then error type {@link SerializationErrorPerUndefinedArrayElement}\n\t * is returned with hopes of being informative.\n\t *\n\t * @system\n\t */\n\texport type JsonForSerializableArrayItem<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[],\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined. */\n\t/* These tests are expected to match those in JsonSerializableImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for exact recursion */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t/* recursion; stop here => */ T,\n\t\t\t\t\t/* test for JSON primitive types or given alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t? /* primitive types or alternative => */ T\n\t\t\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* test for undefined possibility */ undefined extends T\n\t\t\t\t\t\t\t\t\t? /* undefined | ... => */ SerializationErrorPerUndefinedArrayElement\n\t\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t\t\t>\n\t\t\t\t>;\n\n\t/**\n\t * Filters a type `T` for types that become null through JSON serialization.\n\t *\n\t * @system\n\t */\n\texport type JsonForDeserializedArrayItem<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined, symbol, or function. */\n\t/* These tests are expected to match those in JsonDeserializedImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for JSON primitive types or general alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive or replaced types => */ T\n\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t/* exactly replaced => */ T,\n\t\t\t\t\t\t/* test for known types that become null */ T extends undefined | symbol\n\t\t\t\t\t\t\t? /* => */ null\n\t\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t: null | TBlessed\n\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t>;\n\n\t/**\n\t * Checks for a type that is simple class of number and string indexed types to numbers and strings.\n\t *\n\t * @system\n\t */\n\texport type IfEnumLike<\n\t\tT extends object,\n\t\tEnumLike = never,\n\t\tNotEnumLike = unknown,\n\t> = T extends readonly (infer _)[]\n\t\t? /* array => */ NotEnumLike\n\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\tT extends Function\n\t\t\t? /* function => */ NotEnumLike\n\t\t\t: T extends {\n\t\t\t\t\t\t// all numerical indices should refer to a string\n\t\t\t\t\t\treadonly [i: number]: string;\n\t\t\t\t\t\t// string indices may be string or number\n\t\t\t\t\t\treadonly [p: string]: number | string;\n\t\t\t\t\t\t// no symbol indices are allowed\n\t\t\t\t\t\treadonly [s: symbol]: never;\n\t\t\t\t\t}\n\t\t\t\t? /* test for a never or any property */ true extends {\n\t\t\t\t\t\t[K in keyof T]: T[K] extends never ? true : never;\n\t\t\t\t\t}[keyof T]\n\t\t\t\t\t? NotEnumLike\n\t\t\t\t\t: EnumLike\n\t\t\t\t: NotEnumLike;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns IfSame if identical and IfDifferent otherwise.\n\t *\n\t * Implementation derived from https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IfSameType<X, Y, IfSame = unknown, IfDifferent = never> = (<T>() => T extends X\n\t\t? 1\n\t\t: 2) extends <T>() => T extends Y ? 1 : 2\n\t\t? IfSame\n\t\t: IfDifferent;\n\n\t/**\n\t * Test for type equality with tuple of other types.\n\t *\n\t * @typeParam T - Type to find in Tuple.\n\t * @typeParam Tuple - Tuple of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @privateRemarks\n\t * Tests for an exact match of `T` in `Tuple[0]`. If not found,\n\t * recurses with the remainder of the tuple.\n\t */\n\texport type IfExactTypeInTuple<\n\t\tT,\n\t\tTuple extends unknown[],\n\t\tIfMatch = unknown,\n\t\tIfNoMatch = never,\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? IfSameType<T, First, IfMatch, IfExactTypeInTuple<T, Rest, IfMatch, IfNoMatch>>\n\t\t: IfNoMatch;\n\n\t/**\n\t * Test for type equality with union of other types.\n\t *\n\t * @typeParam T - Type to find in Union. If this is itself a union, then all types must be found in Union.\n\t * @typeParam Union - Union of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @remarks\n\t * In a recursive context, use {@link InternalUtilityTypes.IfExactTypeInTuple} to manage ancestry.\n\t *\n\t * @privateRemarks\n\t * Perhaps it is a Typescript defect but a simple check that `T` is `never`\n\t * via `T extends never` does not work as expected in this context.\n\t * Workaround using `IfSameType<..., never,...>`.\n\t * @system\n\t */\n\texport type IfExactTypeInUnion<T, Union, IfMatch = unknown, IfNoMatch = never> = IfSameType<\n\t\tT,\n\t\tnever,\n\t\t/* T is never => */ IfSameType<Union, never, IfMatch, IfNoMatch>,\n\t\t/* T is NOT never => */ IfSameType<T, Extract<Union, T>, IfMatch, IfNoMatch>\n\t>;\n\n\t/**\n\t * Check for a template literal that has $\\{string\\} or $\\{number\\}\n\t * in the pattern. Just `string` and/or `number` also match.\n\t *\n\t * @remarks This works recursively looking at first elements when not\n\t * `string` or `number`. `first` will just be a single character if\n\t * not $\\{string\\} or $\\{number\\}.\n\t *\n\t * @system\n\t */\n\texport type IfVariableStringOrNumber<T, IfVariable, IfLiteral> = `${string}` extends T\n\t\t? IfVariable\n\t\t: number extends T\n\t\t\t? IfVariable\n\t\t\t: T extends `${infer first}${infer rest}`\n\t\t\t\t? string extends first\n\t\t\t\t\t? IfVariable\n\t\t\t\t\t: `${number}` extends first\n\t\t\t\t\t\t? IfVariable\n\t\t\t\t\t\t: IfVariableStringOrNumber<rest, IfVariable, IfLiteral>\n\t\t\t\t: IfLiteral;\n\n\t/**\n\t * Essentially a check for a non-fixed number or string OR a branded key.\n\t *\n\t * @remarks There is no known mechanism to determine the primitive from a\n\t * generic tagged (branded) primitive, such as `X$\\{string\\}` & \\{ foo: \"bar\" \\}.\n\t * There appears to be little use for a branded literal key -- at runtime\n\t * there is no brand; so, two of the same literal with different brands would\n\t * collide. Thus any branded key can usually be considered indexed.\n\t *\n\t * @system\n\t */\n\texport type IfIndexOrBrandedKey<\n\t\tT extends keyof AnyRecord,\n\t\tIfIndexOrBranded,\n\t\tOtherwise,\n\t> = T extends object\n\t\t? /* branded string or number */ IfIndexOrBranded\n\t\t: /* => check for variable */ IfVariableStringOrNumber<T, IfIndexOrBranded, Otherwise>;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns `true` if identical and `false` otherwise.\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IsSameType<X, Y> = IfSameType<X, Y, true, false>;\n\n\t/**\n\t * Checks that type is exactly `object`.\n\t *\n\t * @system\n\t */\n\texport type IsExactlyObject<T extends object> = IsSameType<T, object>;\n\n\t/**\n\t * Any Record type.\n\t *\n\t * @system\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- `any` for property types is required to avoid \"Index signature for type 'string' is missing in type\" in some outside `FlattenIntersection` uses.\n\texport type AnyRecord = Record<keyof any, any>;\n\n\t/**\n\t * Creates a simple object type from an intersection of multiple.\n\t * @privateRemarks\n\t * `T extends AnyRecord` within the implementation encourages tsc to process\n\t * intersections within unions.\n\t *\n\t * @system\n\t */\n\texport type FlattenIntersection<T extends AnyRecord> = T extends AnyRecord\n\t\t? {\n\t\t\t\t[K in keyof T]: T[K];\n\t\t\t}\n\t\t: T;\n\n\t/**\n\t * Convenience constraint for any OpaqueJson* type.\n\t *\n\t * @remarks\n\t * Use in extends check: `T extends AnyOpaqueJsonType`\n\t *\n\t * @system\n\t */\n\texport type AnyOpaqueJsonType =\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t\t| OpaqueJsonSerializable<unknown, any, unknown>\n\t\t| OpaqueJsonDeserialized<unknown, any, unknown>;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Extracts Function portion from an intersection (&) type returning\n\t * the extracted portion in the `function` property or `unknown` if\n\t * no function is found.\n\t * The returned `classification` property has one of three values:\n\t * - \"no Function\" if the type is not a function.\n\t * - \"exactly Function\" if the type is exactly a function.\n\t * - \"Function and more\" if the type is a function and has other properties.\n\t *\n\t * @system\n\t */\n\texport type ExtractFunctionFromIntersection<T extends object> = (T extends new (\n\t\t...args: infer A\n\t) => infer R\n\t\t? new (\n\t\t\t\t...args: A\n\t\t\t) => R\n\t\t: unknown) &\n\t\t(T extends (...args: infer A) => infer R\n\t\t\t? (...args: A) => R\n\t\t\t: unknown) extends infer Functional\n\t\t? {\n\t\t\t\tclassification: unknown extends Functional\n\t\t\t\t\t? \"no Function\"\n\t\t\t\t\t: Functional extends Required<T>\n\t\t\t\t\t\t? \"exactly Function\"\n\t\t\t\t\t\t: \"Function and more\";\n\t\t\t\tfunction: Functional;\n\t\t\t}\n\t\t: never;\n\n\t/**\n\t * Returns `Filtered` & any Function intersection from `Original`.\n\t * If `Original` is exactly a Function, then `Filtered` is left out\n\t * under the assumption that it is not useful/applicable.\n\t *\n\t * @system\n\t */\n\texport type FilterPreservingFunction<\n\t\tOriginal extends object,\n\t\tFiltered,\n\t> = ExtractFunctionFromIntersection<Original> extends {\n\t\tclassification: infer TClassification;\n\t\tfunction: infer TFunction;\n\t}\n\t\t? TClassification extends \"exactly Function\"\n\t\t\t? TFunction\n\t\t\t: TFunction & Filtered\n\t\t: never;\n\n\t/**\n\t * Replaces any instance where a type T recurses into itself or a portion of\n\t * itself with TRecursionMarker.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam TRecursionMarker - Replacement marker type.\n\t * @typeParam Controls - Allowances are preserved as-is.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @remarks\n\t * Filtering applied to class instances with non-public properties will not\n\t * preserve the class instance unless those classes are known and listed as\n\t * allowances via `Controls`.\n\t *\n\t * @privateRemarks\n\t * This implementation handles functions including function with properties.\n\t * There are no known cases where replacing recursion under such types make\n\t * a difference. Either the function (whole type) is allowed by the Json\n\t * filters or function is not allowed at all.\n\t * If the function portion is found to be problematic later, then could use\n\t * `T extends Function ? T : ...` to ignore function objects.\n\t *\n\t * @system\n\t */\n\texport type ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tTRecursionMarker,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for recursion */\n\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion => use replacement */ TRecursionMarker\n\t\t: /* force union separation hereafter */ T extends infer _\n\t\t\t? /* test for recursion among union elements */\n\t\t\t\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? TRecursionMarker\n\t\t\t\t: /* test for general allowance */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* allowed extension type => */ T\n\t\t\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact allowed type => */ T\n\t\t\t\t\t\t: T extends object\n\t\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tTRecursionMarker,\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* non-object => T as is */ T\n\t\t\t: never;\n\n\t/**\n\t * Replaces any instances of \"allowed\" types and recursion within with `never`.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam Controls - Allowances to replace.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @system\n\t */\n\texport type ReplaceAllowancesAndRecursionWithNever<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for exact recursion first */ IfExactTypeInTuple<\n\t\tT,\n\t\tTAncestorTypes,\n\t\ttrue,\n\t\t\"no match\"\n\t> extends true\n\t\t? /* recursion => */ never\n\t\t: /* test for general allowance (also forces union separation) */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t? /* allowed extension type => */ never\n\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact allowed type => */ never\n\t\t\t\t: /* test for recursion among union elements */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* recursion => */ never\n\t\t\t\t\t: T extends object\n\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceAllowancesAndRecursionWithNever<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* non-object => T as is */ T;\n\n\t/**\n\t * Test for non-public properties (which can only exist on class instance types).\n\t *\n\t * Returns `HasNonPublic` if `T` deeply may contain a private or protected field\n\t * and `OnlyPublics` otherwise.\n\t *\n\t * @remarks\n\t * Compare original (unprocessed) to filtered case that has `never` where\n\t * recursing or where allowed exception types are used.\n\t *\n\t * Note that this a test of the type and not the actual data. So, if an\n\t * interface is given as `T` where implemented by a class, any private or\n\t * protected fields within the class will not be detected.\n\t *\n\t * @system\n\t */\n\texport type IfNonPublicProperties<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tHasNonPublic = never,\n\t\tOnlyPublics = unknown,\n\t> = ReplaceAllowancesAndRecursionWithNever<T, Controls> extends T\n\t\t? OnlyPublics\n\t\t: HasNonPublic;\n\n\t/**\n\t * Union of all types in a tuple.\n\t *\n\t * @system\n\t */\n\texport type TupleToUnion<T extends unknown[]> = T[number];\n\n\t// #region JsonSerializable implementation\n\n\t/**\n\t * Outer implementation of {@link JsonSerializable} handling meta cases\n\t * like classes (with non-public properties).\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls> & {\n\t\t\t/**\n\t\t\t * See {@link JsonSerializableOptions} for meaning and expected use.\n\t\t\t */\n\t\t\tIgnoreInaccessibleMembers?: \"ignore-inaccessible-members\";\n\t\t},\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute type could be extracted to helper type, but is kept explicit here\n\t\t// to make JsonTypeWith and OpaqueJsonSerializable show explicitly in results for\n\t\t// users, rather than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute:\n\t\t\t| JsonTypeWith<\n\t\t\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t\t\t: never)\n\t\t\t\t\t| (Options extends { AllowExtensionOf: unknown }\n\t\t\t\t\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t: never)\n\t\t\t >\n\t\t\t| OpaqueJsonSerializable<\n\t\t\t\t\tunknown,\n\t\t\t\t\tOptions extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [],\n\t\t\t\t\tOptions extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never\n\t\t\t >;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy FilterControlsWithSubstitution, but Typescript wants a check */\n\t\t\tControls extends FilterControlsWithSubstitution\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: Options extends { IgnoreInaccessibleMembers: \"ignore-inaccessible-members\" }\n\t\t\t\t\t? JsonSerializableFilter<T, Controls, TAncestorTypes, TNextAncestor>\n\t\t\t\t\t: /* test for non-public properties (class instance type) */\n\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in primitives that may be branded to ignore intersection classes\n\t\t\t\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t? /* hidden props => test if it is array properties that are the problem */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonSerializableImpl<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: /* test for potentially branded primitive (intersection with a supported primitive) */\n\t\t\t\t\t\t\t\tT extends boolean | number | string\n\t\t\t\t\t\t\t\t? /* assume intersection is branding and allow as-is => */ T\n\t\t\t\t\t\t\t\t: /* not array => error */ SerializationErrorPerNonPublicProperties\n\t\t\t\t\t\t: /* no hidden properties => apply filtering => */ JsonSerializableFilter<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\tTNextAncestor\n\t\t\t\t\t\t\t>\n\t\t\t: never /* FilterControlsWithSubstitution assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonSerializable}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} and {@link OpaqueJsonDeserialized} instances\n\t * are limited to `Controls` given context supports.\n\t * `T` from the original Opaque type is preserved. In the case that this now\n\t * produces an improper type such as a `bigint` being let through that is no\n\t * longer supported, then the variance of `Controls` is expected to raise\n\t * the incompatibility error.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableOpaqueAllowances<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControlsWithSubstitution,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t/* infer underlying data type */ T extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? T extends OpaqueJsonSerializable<TData, any, unknown> &\n\t\t\t\tOpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]> &\n\t\t\t\t\tOpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t: T extends OpaqueJsonSerializable<TData, any, unknown>\n\t\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t\t: T extends OpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t\t\t? OpaqueJsonDeserialized<\n\t\t\t\t\t\t\tTData,\n\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t>\n\t\t\t\t\t: \"internal error: failed to determine OpaqueJson* type\"\n\t\t: never;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Helper for {@link JsonSerializableFilter} to determine if a property may\n\t * be `undefined` and selects from options for result.\n\t * Since `unknown` is a superset of `undefined`, it is given a special case.\n\t * Additionally since index signatures are inherently optional, `unknown` typed\n\t * values are treated as not undefined (`Result[\"Otherwise\"]`).\n\t *\n\t * @system\n\t */\n\texport type IfPossiblyUndefinedProperty<\n\t\tTKey extends keyof AnyRecord,\n\t\tTValue,\n\t\tResult extends {\n\t\t\tIfPossiblyUndefined: unknown;\n\t\t\tIfUnknownNonIndexed: unknown;\n\t\t\tOtherwise: unknown;\n\t\t},\n\t> = undefined extends TValue\n\t\t? unknown extends TValue\n\t\t\t? IfIndexOrBrandedKey<TKey, Result[\"Otherwise\"], Result[\"IfUnknownNonIndexed\"]>\n\t\t\t: Result[\"IfPossiblyUndefined\"]\n\t\t: Result[\"Otherwise\"];\n\n\t/**\n\t * Core implementation of {@link JsonSerializable}.\n\t *\n\t * @privateRemarks\n\t * Filtering through a single layer of recursion is all that is required\n\t * when using in prescribed filter scenario.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableFilter<\n\t\tT,\n\t\tControls extends FilterControlsWithSubstitution,\n\t\tTAncestorTypes extends unknown[],\n\t\tTNextAncestor = T,\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for recursion */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact recursion; stop here => */ T\n\t\t\t\t: /* test for JSON Encodable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t\t| null\n\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t\t: /* test for exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\t/* test for not a function */ Extract<T, Function> extends never\n\t\t\t\t\t\t\t? /* not a function => test for object */ T extends object\n\t\t\t\t\t\t\t\t? /* object => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForSerializableArrayItem<\n\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\t\t\t\t\tJsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t\t? /* `object` => */ NonNullJsonObjectWith<\n\t\t\t\t\t\t\t\t\t\t\t\tTupleToUnion<Controls[\"AllowExactly\"]> | Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t\t: /* test for OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonSerializableOpaqueAllowances<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* required properties are recursed and may not have undefined values. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as RequiredNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]-?: IfPossiblyUndefinedProperty<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfPossiblyUndefined: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `undefined` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfUnknownNonIndexed: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `unknown` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tOtherwise: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* optional properties are recursed and, when exactOptionalPropertyTypes is\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t false, are allowed to preserve undefined value type. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as OptionalNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* symbol properties are rejected */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T & symbol]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t: /* not an object => */ never\n\t\t\t\t\t\t\t: /* function => */ never;\n\n\t// #endregion\n\n\t/**\n\t * Sentinel type for use when marking points of recursion (in a recursive type).\n\t * Type is expected to be unique, though no lengths are taken to ensure that.\n\t *\n\t * @system\n\t */\n\texport interface RecursionMarker {\n\t\t[RecursionMarkerSymbol]: typeof RecursionMarkerSymbol;\n\t}\n\n\t// #region JsonDeserialized implementation\n\n\t/**\n\t * Outer implementation of {@link JsonDeserialized} handling meta cases\n\t * like recursive types.\n\t *\n\t * @remarks\n\t * If no modification is needed (`T` is exactly deserializable), `T` will\n\t * be the result.\n\t *\n\t * Upon recursion with `T` that requires modification, `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing.\n\t * Caller will need to unwrap the type to continue processing.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls>,\n\t\tTypeUnderRecursion extends boolean = false,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute types could be extracted to helper type, but are kept explicit here\n\t\t// to make JsonTypeWith/NonNullJsonObjectWith show explicitly in results for users, rather\n\t\t// than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute: JsonTypeWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tDegenerateNonNullObjectSubstitute: NonNullJsonObjectWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tRecursionMarkerAllowed: never;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy DeserializedFilterControls, but Typescript wants a check */\n\t\t\tControls extends DeserializedFilterControls\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tRecursionMarker,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t// Also preserve OpaqueJson* types\n\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t> extends infer TNoRecursionAndOnlyPublics\n\t\t\t\t\t? /* test for no change from filtered type */ IsSameType<\n\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\tJsonDeserializedFilter<\n\t\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf: Controls[\"AllowExtensionOf\"];\n\t\t\t\t\t\t\t\t\tDegenerateSubstitute: Controls[\"DegenerateSubstitute\"];\n\t\t\t\t\t\t\t\t\tDegenerateNonNullObjectSubstitute: Controls[\"DegenerateNonNullObjectSubstitute\"];\n\t\t\t\t\t\t\t\t\tRecursionMarkerAllowed: RecursionMarker;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* same (no filtering needed) => test for non-public\n\t\t\t\t\t\t properties (class instance type) */\n\t\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t\t\t\t// primitives as JsonDeserializedFilter will allow them as\n\t\t\t\t\t\t\t\t// extensions of the primitives. Should there be a need to\n\t\t\t\t\t\t\t\t// explicitly allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t\t? /* hidden props => apply filtering to avoid retaining\n\t\t\t\t\t\t\t exact class except for any classes in allowances =>\n\t\t\t\t\t\t\t\t test for known recursion */\n\t\t\t\t\t\t\t\tTypeUnderRecursion extends false\n\t\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* no hidden properties => deserialized T is just T */\n\t\t\t\t\t\t\t\tT\n\t\t\t\t\t\t: /* filtering is needed => test for known recursion */ TypeUnderRecursion extends false\n\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t: /* unreachable else for infer */ never\n\t\t\t: never /* DeserializedFilterControls assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.JsonDeserializedFilter} up until\n\t * `T` is found to be a match of an ancestor type. At that point `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing, if\n\t * modification is needed. Caller will need to unwrap the type to continue processing.\n\t * If no modification is needed, then `T` will be the result.\n\t *\n\t * @privateRemarks Exact recursion pattern employed should allow shortcut\n\t * test to return `OpaqueJsonDeserialized<T>` from here when the exact\n\t * recursion match is the first ancestor type in tuple as it must have been\n\t * processed and found to need modification.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedRecursion<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTAncestorTypes extends object[],\n\t> = IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion found => reprocess that recursive type directly to avoid\n\t\t any collateral damage from ancestor type that required modification.\n\t\t\t Further recursion will not happen during processing. Either:\n\t\t\t - the type requires modification and the `TypeUnderRecursion=true`\n\t\t\t arg will result in `OpaqueJsonDeserialized<T>` wrapper OR\n\t\t\t - no change is needed from this point and `T` will result. */\n\t\t\tJsonDeserializedImpl<T, Controls, true>\n\t\t: T extends object\n\t\t\t? IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? JsonDeserializedImpl<T, Controls, true>\n\t\t\t\t: /* no recursion yet detected => */ JsonDeserializedFilter<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls,\n\t\t\t\t\t\t[...TAncestorTypes, T]\n\t\t\t\t\t>\n\t\t\t: /* not an object (no recursion) => */ JsonDeserializedFilter<\n\t\t\t\t\tT,\n\t\t\t\t\tControls,\n\t\t\t\t\tTAncestorTypes\n\t\t\t\t>;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonDeserialized}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} instances are converted to {@link OpaqueJsonDeserialized}.\n\t * The `AllowExactly` and `AllowExtensionOf` properties are set to match the given `Controls`.\n\t * The data type is kept exactly as-is to avoid processing in generic contexts that can't\n\t * produce a meaningful result. The data type should always be filtered through\n\t * {@link JsonDeserialized} when {@link OpaqueJsonDeserialized} is cracked open. So, really\n\t * the filtering is just deferred.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedOpaqueConversion<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControls,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\tT extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? OpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t: \"internal error: failed to determine OpaqueJson* type\";\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Core implementation of {@link JsonDeserialized}.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedFilter<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\t// Always start with object portion of self as ancestor. Filtering will\n\t\t// not apply past recursion (nested occurrence of this).\n\t\tTAncestorTypes extends object[] = [Extract<T, object>],\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for deserializable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t: /* test for given exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"not found\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t: /* test for object */ T extends object\n\t\t\t\t\t\t? /* object => */ ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t? /* exactly function => */ never\n\t\t\t\t\t\t\t: /* not exactly a function (Function portion, if any, is omitted) */\n\t\t\t\t\t\t\t\t/* => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForDeserializedArrayItem<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\tJsonDeserializedRecursion<T[K], Controls, TAncestorTypes>\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t? /* `object` => */ Controls[\"DegenerateNonNullObjectSubstitute\"]\n\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t: /* test for matching OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonDeserializedOpaqueConversion<T, Controls>\n\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with symbol keys or wholly unsupported values are removed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with defined values are recursed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolWithDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* literal properties that may have undefined values are optional */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* not an object => */ never;\n\n\t// #endregion\n\n\t// #region *Readonly implementations\n\n\t/**\n\t * Recursion limit is the count of `+` that prefix it when string.\n\t *\n\t * @system\n\t */\n\texport type RecursionLimit = `+${string}` | 0;\n\n\t/**\n\t * If `T` is a `Map<K,V>` or `ReadonlyMap<K,V>`, returns `ReadonlyMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlyMap<infer K, infer V>\n\t\t? Map<K, V> extends DeepenedGenerics\n\t\t\t? ReadonlyMap<\n\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t>\n\t\t\t: ReadonlyMap<K, V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Set<TSet>` or `ReadonlySet<TSet>`, returns `ReadonlySet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlySet<infer V>\n\t\t? Set<V> extends DeepenedGenerics\n\t\t\t? ReadonlySet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: ReadonlySet<V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `IFluidHandle<THandle>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `THandle` generic.\n\t * `Else` is returned if not an `IFluidHandle`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInFluidHandleIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Readonly<IFluidHandle<infer V>>\n\t\t? IFluidHandle<V> extends DeepenedGenerics\n\t\t\t? Readonly<IFluidHandle<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>>\n\t\t\t: Readonly<T>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Promise<TPromise>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `TPromise` generic.\n\t * `Else` is returned if not a `Promise`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInPromiseIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Promise<infer V>\n\t\t? Promise<V> extends DeepenedGenerics\n\t\t\t? Promise<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: T\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakMap<K,V>`, returns immutable `WeakMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakMap<infer K, infer V>, \"delete\" | \"set\">\n\t\t? WeakMap<K, V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakMap<\n\t\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t\t>,\n\t\t\t\t\t\"delete\" | \"set\"\n\t\t\t\t>\n\t\t\t: Omit<WeakMap<K, V>, \"delete\" | \"set\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakSet<TSet>`, returns immutable `WeakSet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic weak set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakSet<infer V>, \"add\" | \"delete\">\n\t\t? WeakSet<V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakSet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>,\n\t\t\t\t\t\"add\" | \"delete\"\n\t\t\t\t>\n\t\t\t: Omit<WeakSet<V>, \"add\" | \"delete\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a {@link ReadonlySupportedGenerics}, `T` is returned as\n\t * its immutable version, and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `T`s generics.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInGenerics<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics,\n\t\tNoDepthOrRecurseLimit,\n\t\tDeepenReadonlyInSetIfEnabled<\n\t\t\tT,\n\t\t\tDeepenedGenerics,\n\t\t\tNoDepthOrRecurseLimit,\n\t\t\tDeepenReadonlyInWeakMapIfEnabled<\n\t\t\t\tT,\n\t\t\t\tDeepenedGenerics,\n\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\tDeepenReadonlyInWeakSetIfEnabled<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\tDeepenReadonlyInPromiseIfEnabled<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\tDeepenReadonlyInFluidHandleIfEnabled<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\t\tElse\n\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t>\n\t>;\n\n\t/**\n\t * Returns an `ErasedType` or \"branded\" primitive type as-is, or `Else` if not.\n\t * @typeParam T - Type to test.\n\t * @typeParam Else - Type to return if not `ErasedType` or \"branded\" primitive.\n\t *\n\t * @system\n\t */\n\texport type PreserveErasedTypeOrBrandedPrimitive<\n\t\tT extends object,\n\t\tElse,\n\t> = /* Test for erased type */ T extends ErasedType<infer _>\n\t\t? /* erased type => keep as-is */ T\n\t\t: /* Test for branded primitive */ T extends infer Brand &\n\t\t\t\t\t(boolean | number | string | symbol | bigint)\n\t\t\t? // Should just return T here, but TypeScript appears to produce `never` when doing so.\n\t\t\t\t// Workaround by inferring the Primitive type and returning intersection with B.\n\t\t\t\tT extends Brand & infer Primitive\n\t\t\t\t? /* [potentially] branded type => \"as-is\" */ Primitive & Brand\n\t\t\t\t: /* Should never be reached */ T\n\t\t\t: Else;\n\n\t/**\n\t * De-multiplexing implementation of {@link DeepReadonly} and {@link ShallowReadonly}\n\t * selecting behavior based on `NoDepthOrRecurseLimit`.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant. Its importance is that other utilities common to\n\t * readonly transformation may use `NoDepthOrRecurseLimit` to return the the\n\t * same processing algorithm.\n\t *\n\t * @system\n\t */\n\texport type ReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t> = /* test for no depth */ NoDepthOrRecurseLimit extends \"Shallow\"\n\t\t? /* no depth => */ ShallowReadonlyImpl<T, DeepenedGenerics>\n\t\t: /* test for no limit */ NoDepthOrRecurseLimit extends \"NoLimit\"\n\t\t\t? /* no limit => */ DeepReadonlyRecursingInfinitely<T, DeepenedGenerics>\n\t\t\t: /* limited */ DeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>;\n\n\t// #region ShallowReadonly implementation\n\n\t/**\n\t * Outer implementation of {@link ShallowReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility can be reentrant when generics are deepened.\n\t *\n\t * @system\n\t */\n\texport type ShallowReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\"Shallow\",\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<T, /* basic type => */ Readonly<T>>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\n\t/**\n\t * Outer implementation of {@link DeepReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `RecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends DeepReadonlyRecursionLimit,\n\t> = ReadonlyImpl<T, DeepenedGenerics, RecurseLimit>;\n\n\t// #region DeepReadonly infinite recursion implementation\n\n\t/**\n\t * Simple implementation of {@link DeepReadonly} that may handle limited recursive types.\n\t * In unhandled cases, TypeScript will produce:\n\t * ts(2589): Type instantiation is excessively deep and possibly infinite.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursingInfinitely<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\t// test for array of known recursive type: JsonTypeWith\n\t\t\t\tT extends readonly ReadonlyJsonTypeWith<infer Alternates>[]\n\t\t\t\t\t? // Make sure this is exactly that case (many arrays will extend JsonTypeWith)\n\t\t\t\t\t\t// Note that `true extends IfExactTypeInTuple` is used over\n\t\t\t\t\t\t// if-else form as the else branch would be evaluated as input to\n\t\t\t\t\t\t// `IfExactTypeInTuple` and that could lead to infinite recursion.\n\t\t\t\t\t\ttrue extends IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[JsonTypeWith<Alternates>[], readonly ReadonlyJsonTypeWith<Alternates>[]]\n\t\t\t\t\t\t>\n\t\t\t\t\t\t? readonly ReadonlyJsonTypeWith<\n\t\t\t\t\t\t\t\tDeepReadonlyRecursingInfinitely<Alternates, DeepenedGenerics>\n\t\t\t\t\t\t\t>[]\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: /* not JSON array => */ DeepenReadonlyInGenerics<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\"NoLimit\",\n\t\t\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #region DeepReadonly limited recursion implementation\n\n\t/**\n\t * Core implementation of {@link DeepReadonly} handling meta cases\n\t * like recursive types a limited number of times.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `NoDepthOrRecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyLimitingRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends RecursionLimit,\n\t> = /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tRecursionMarker,\n\t\t{ AllowExactly: []; AllowExtensionOf: never }\n\t> extends infer TNoRecursionAndOnlyPublics\n\t\t? /* test for no change from altered type (excluding non-publics) */ IsSameType<\n\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\tDeepReadonlyWorker<TNoRecursionAndOnlyPublics, DeepenedGenerics, 0>\n\t\t\t> extends true\n\t\t\t? /* same (no filtering needed) => test for non-public properties (class instance type) */\n\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\tT,\n\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t// primitives as DeepReadonlyWorker will allow them as\n\t\t\t\t\t// extensions of the primitives. Should there need a need to\n\t\t\t\t\t// explicit allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t{ AllowExactly: []; AllowExtensionOf: never },\n\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\"only publics\"\n\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t? /* hidden props => apply filtering => */\n\t\t\t\t\tDeepReadonlyWorker<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t\t>\n\t\t\t\t: /* no hidden properties => readonly T is just T */\n\t\t\t\t\tT\n\t\t\t: /* filtering is needed => */ DeepReadonlyWorker<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>\n\t\t: /* unreachable else for infer */ never;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.DeepReadonlyWorker} up to `RecurseLimit` times.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = T extends TAncestorTypes\n\t\t? RecurseLimit extends `+${infer RecursionRemainder}`\n\t\t\t? /* Now that specific recursion is found, process that recursive type\n\t\t\t directly to avoid any collateral damage from ancestor type that\n\t\t\t required modification. */\n\t\t\t\tDeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecursionRemainder extends RecursionLimit ? RecursionRemainder : 0\n\t\t\t\t>\n\t\t\t: T\n\t\t: DeepReadonlyWorker<T, DeepenedGenerics, RecurseLimit, TAncestorTypes | T>;\n\n\t/**\n\t * Core implementation of {@link InternalUtilityTypes.DeepReadonlyLimitingRecursion}.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyWorker<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = /* test for object */ T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecurseLimit,\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursion<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\tRecurseLimit,\n\t\t\t\t\t\t\t\tTAncestorTypes\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #endregion\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exposedInternalUtilityTypes.js","sourceRoot":"","sources":["../src/exposedInternalUtilityTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;GAEG;AACH,MAAM,qBAAqB,GAAkB,MAAM,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @rushstack/no-new-null */\n\nimport type { ErasedType } from \"./erasedType.js\";\nimport type { IFluidHandle } from \"./handles.js\";\nimport type {\n\tSerializationErrorPerNonPublicProperties,\n\tSerializationErrorPerUndefinedArrayElement,\n} from \"./jsonSerializationErrors.js\";\nimport type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from \"./jsonType.js\";\nimport type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from \"./opaqueJson.js\";\n\n/**\n * Unique symbol for recursion meta-typing.\n */\nconst RecursionMarkerSymbol: unique symbol = Symbol(\"recursion here\");\n\n/**\n * Union of types that {@link DeepReadonly} and {@link ShallowReadonly}\n * recognize to generate immutable form and optionally can alter their\n * type parameters.\n *\n * @privateRemarks\n * WeakRef should be added when lib is updated to ES2021 or later.\n *\n * @beta\n */\nexport type ReadonlySupportedGenerics =\n\t| IFluidHandle\n\t| Map<unknown, unknown>\n\t| Promise<unknown>\n\t| Set<unknown>\n\t| WeakMap<object, unknown>\n\t| WeakSet<object>;\n\n/**\n * Limit on processing recursive types.\n * Use of `\"NoLimit\"` may result in error:\n * \"ts(2589): Type instantiation is excessively deep and possibly infinite\".\n * In such cases, use string literal with some prefix series of `+`\n * characters. The length of `+` character sequence indicates the recursion\n * depth limit when a recursive type is found. Use of `0` will stop applying\n * `DeepReadonly` at the first point recursion is detected.\n *\n * @beta\n * @system\n */\nexport type DeepReadonlyRecursionLimit = \"NoLimit\" | 0 | `+${string}`;\n\n/**\n * Collection of utility types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @privateRemarks\n * There are ony three intentional exports from this module:\n * - {@link InternalUtilityTypes.IfSameType | IfSameType}\n * - {@link InternalUtilityTypes.JsonDeserializedImpl | JsonDeserializedImpl }\n * - {@link InternalUtilityTypes.JsonSerializableImpl | JsonSerializableImpl }\n *\n * api-extractor will allow `export` to be removed from others but generates\n * api-report a little oddly with a rogue `{};` floating at end of namespace\n * in api.md file. It will promote all of the support types to appear as\n * exported anyway. All in namespace are left exported to avoid api-extractor\n * potentially failing to validate other modules correctly.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalUtilityTypes {\n\t/**\n\t * Meta-type for controlling filtering utilities.\n\t *\n\t * @system\n\t */\n\texport interface FilterControls {\n\t\t/**\n\t\t * Tuple of exact types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Only exact types matching specification will be preserved unaltered.\n\t\t */\n\t\tAllowExactly: unknown[];\n\n\t\t/**\n\t\t * General types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Any type satisfying specification will be preserved unaltered.\n\t\t */\n\t\tAllowExtensionOf: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling filtering utilities that additionally supplies\n\t * a substitute type for degenerate cases.\n\t *\n\t * @system\n\t */\n\tinterface FilterControlsWithSubstitution extends FilterControls {\n\t\t/**\n\t\t * Type to use for degenerate cases like `unknown` or `any`.\n\t\t * Typically this will be `JsonTypeWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateSubstitute: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling deserialized filtering utilities.\n\t *\n\t * @system\n\t */\n\tinterface DeserializedFilterControls extends FilterControlsWithSubstitution {\n\t\t/**\n\t\t * Type to use for degenerate `object` case.\n\t\t * Typically this will be `NonNullJsonObjectWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateNonNullObjectSubstitute: unknown;\n\n\t\t/**\n\t\t * Either `RecursionMarker` when filtering after recursion has been replace or `never`\n\t\t */\n\t\tRecursionMarkerAllowed: unknown; // Can be RecursionMarker ?\n\t}\n\n\t/**\n\t * Returns non-symbol keys for optional properties of an object type.\n\t * This excludes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as OptionalNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type OptionalNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? never : K;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol keys for required properties of an object type.\n\t * This includes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as RequiredNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type RequiredNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? K : never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns Result.WhenSomethingDeserializable if T is sometimes at least a\n\t * partially deserializable type, otherwise Result.WhenNeverDeserializable.\n\t * Fully not deserializable (bigints, symbols, undefined and functions without\n\t * other properties less overlap with T*Exception) produce Result.WhenNeverDeserializable.\n\t * An object would have a defined result even if parts of its content are\n\t * not deserializable.\n\t *\n\t * @param Result - Result type with two properties. One property must always\n\t * be `never` as `T` maybe a union of never deserializable and at least\n\t * partially deserializable types and the result is a union of Result.*.\n\t *\n\t * @privateRemarks\n\t * If `Result.WhenSomethingDeserializable` was `true` and\n\t * `Result.WhenNeverDeserializable` was `false`, then the return type\n\t * for type `T` would be `boolean` for a sometimes deserializable type.\n\t *\n\t * @system\n\t */\n\texport type TestDeserializabilityOf<\n\t\tT,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tResult extends\n\t\t\t| { WhenSomethingDeserializable: unknown; WhenNeverDeserializable: never }\n\t\t\t| { WhenSomethingDeserializable: never; WhenNeverDeserializable: unknown },\n\t> = /* ensure working with more than never */ T extends never\n\t\t? /* never => */ Result[\"WhenNeverDeserializable\"]\n\t\t: /* check for extends exception */ T extends TExtendsException\n\t\t\t? /* extends exception => */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t: /* no extends exception => check for exact exception */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTExactExceptions,\n\t\t\t\t\t/* exact exception => */ Result[\"WhenSomethingDeserializable\"],\n\t\t\t\t\t/* no exception => check for only non-serializable value types */ T extends\n\t\t\t\t\t\t| bigint\n\t\t\t\t\t\t| symbol\n\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact `U`s from `T`\n\t * rather than any type that extends `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactly<T, U> = IfSameType<T, U, never, T>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact members of `U` from `T`\n\t * rather than any type that extends members of `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactlyInTuple<T, TupleOfU extends unknown[]> = IfExactTypeInTuple<\n\t\tT,\n\t\tTupleOfU,\n\t\tnever,\n\t\tT\n\t>;\n\n\t/**\n\t * Similar to `Omit` but operates on tuples.\n\t * Removes elements of `Tuple` that extend `U`.\n\t *\n\t * @system\n\t */\n\texport type OmitFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitFromTuple<Rest, U, First extends U ? Accumulated : [...Accumulated, First]>\n\t\t: Accumulated;\n\n\t/**\n\t * Similar to `OmitFromTuple` but removes only exact matches of U.\n\t * Removes elements of `Tuple` that are exactly `U`.\n\t *\n\t * @remarks If `U` is a union, then only exactly matching union elements of `Tuple` are removed.\n\t * @system\n\t */\n\texport type OmitExactlyFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitExactlyFromTuple<Rest, U, IfSameType<First, U, Accumulated, [...Accumulated, First]>>\n\t\t: Accumulated;\n\n\t/**\n\t * Returns non-symbol keys for defined, (likely) serializable properties of an\n\t * object type. Literal keys with fully unsupported properties (undefined, symbol,\n\t * and bigint) and sometimes unsupported (functions) are excluded. An exception to\n\t * that is when there are supported types in union with just bigint. Indexed keys\n\t * are only excluded when there are no supported properties.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolWithDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: /* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\tExcludeExactlyInTuple<\n\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t? IfSameType<\n\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t/* value might not be supported => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t>,\n\t\t\t\t\t\t/* extract types that might lead to missing property */ Extract<\n\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t/* types that might lead to missing property, except `bigint` */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t\t? /* all types are supported plus possibly `bigint` => */\n\t\t\t\t\t\t\t\t/* check for only `bigint` remaining */ IfSameType<\n\t\t\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t\t\tbigint,\n\t\t\t\t\t\t\t\t\t/* only `bigint` => nothing supported */ never,\n\t\t\t\t\t\t\t\t\t/* exclusively supported types (and maybe `bigint`) or exactly `never` */\n\t\t\t\t\t\t\t\t\t/* => check for `never` */ T[K] extends never ? never : K\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* value might not be supported => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: /* => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: /* => exclude K */ never;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t: never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol, literal keys for partially supported properties of an object type.\n\t * Keys with only unsupported properties (undefined, symbol, bigint, and\n\t * functions without other properties) are excluded.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithPossiblyDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: IfIndexOrBrandedKey<\n\t\t\t\tK,\n\t\t\t\t/* indexed => exclude K */ never,\n\t\t\t\t/* literal => ... */\n\t\t\t\t/* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\t\tExcludeExactlyInTuple<\n\t\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t\t? Extract<\n\t\t\t\t\t\t\tIfSameType<PossibleTypeLessAllowed, unknown, undefined, PossibleTypeLessAllowed>,\n\t\t\t\t\t\t\t/* types that might lead to missing property */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t? /* exclusively supported types or exactly `never` */ never\n\t\t\t\t\t\t: /* at least some unsupported type => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: K;\n\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: never;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t>;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Filters a type `T` for `undefined` that is not viable in an array (or tuple) that\n\t * must go through JSON serialization.\n\t * If `T` is `undefined`, then error type {@link SerializationErrorPerUndefinedArrayElement}\n\t * is returned with hopes of being informative.\n\t *\n\t * @system\n\t */\n\texport type JsonForSerializableArrayItem<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[],\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined. */\n\t/* These tests are expected to match those in JsonSerializableImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for exact recursion */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t/* recursion; stop here => */ T,\n\t\t\t\t\t/* test for JSON primitive types or given alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t? /* primitive types or alternative => */ T\n\t\t\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* test for undefined possibility */ undefined extends T\n\t\t\t\t\t\t\t\t\t? /* undefined | ... => */ SerializationErrorPerUndefinedArrayElement\n\t\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t\t\t>\n\t\t\t\t>;\n\n\t/**\n\t * Filters a type `T` for types that become null through JSON serialization.\n\t *\n\t * @system\n\t */\n\texport type JsonForDeserializedArrayItem<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined, symbol, or function. */\n\t/* These tests are expected to match those in JsonDeserializedImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for JSON primitive types or general alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive or replaced types => */ T\n\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t/* exactly replaced => */ T,\n\t\t\t\t\t\t/* test for known types that become null */ T extends undefined | symbol\n\t\t\t\t\t\t\t? /* => */ null\n\t\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t: null | TBlessed\n\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t>;\n\n\t/**\n\t * Checks for a type that is simple class of number and string indexed types to numbers and strings.\n\t *\n\t * @system\n\t */\n\texport type IfEnumLike<\n\t\tT extends object,\n\t\tEnumLike = never,\n\t\tNotEnumLike = unknown,\n\t> = T extends readonly (infer _)[]\n\t\t? /* array => */ NotEnumLike\n\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\tT extends Function\n\t\t\t? /* function => */ NotEnumLike\n\t\t\t: T extends {\n\t\t\t\t\t\t// all numerical indices should refer to a string\n\t\t\t\t\t\treadonly [i: number]: string;\n\t\t\t\t\t\t// string indices may be string or number\n\t\t\t\t\t\treadonly [p: string]: number | string;\n\t\t\t\t\t\t// no symbol indices are allowed\n\t\t\t\t\t\treadonly [s: symbol]: never;\n\t\t\t\t\t}\n\t\t\t\t? /* test for a never or any property */ true extends {\n\t\t\t\t\t\t[K in keyof T]: T[K] extends never ? true : never;\n\t\t\t\t\t}[keyof T]\n\t\t\t\t\t? NotEnumLike\n\t\t\t\t\t: EnumLike\n\t\t\t\t: NotEnumLike;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns IfSame if identical and IfDifferent otherwise.\n\t *\n\t * Implementation derived from https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IfSameType<X, Y, IfSame = unknown, IfDifferent = never> = (<T>() => T extends X\n\t\t? 1\n\t\t: 2) extends <T>() => T extends Y ? 1 : 2\n\t\t? IfSame\n\t\t: IfDifferent;\n\n\t/**\n\t * Test for type equality with tuple of other types.\n\t *\n\t * @typeParam T - Type to find in Tuple.\n\t * @typeParam Tuple - Tuple of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @privateRemarks\n\t * Tests for an exact match of `T` in `Tuple[0]`. If not found,\n\t * recurses with the remainder of the tuple.\n\t */\n\texport type IfExactTypeInTuple<\n\t\tT,\n\t\tTuple extends unknown[],\n\t\tIfMatch = unknown,\n\t\tIfNoMatch = never,\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? IfSameType<T, First, IfMatch, IfExactTypeInTuple<T, Rest, IfMatch, IfNoMatch>>\n\t\t: IfNoMatch;\n\n\t/**\n\t * Test for type equality with union of other types.\n\t *\n\t * @typeParam T - Type to find in Union. If this is itself a union, then all types must be found in Union.\n\t * @typeParam Union - Union of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @remarks\n\t * In a recursive context, use {@link InternalUtilityTypes.IfExactTypeInTuple} to manage ancestry.\n\t *\n\t * @privateRemarks\n\t * Perhaps it is a Typescript defect but a simple check that `T` is `never`\n\t * via `T extends never` does not work as expected in this context.\n\t * Workaround using `IfSameType<..., never,...>`.\n\t * @system\n\t */\n\texport type IfExactTypeInUnion<T, Union, IfMatch = unknown, IfNoMatch = never> = IfSameType<\n\t\tT,\n\t\tnever,\n\t\t/* T is never => */ IfSameType<Union, never, IfMatch, IfNoMatch>,\n\t\t/* T is NOT never => */ IfSameType<T, Extract<Union, T>, IfMatch, IfNoMatch>\n\t>;\n\n\t/**\n\t * Check for a template literal that has $\\{string\\} or $\\{number\\}\n\t * in the pattern. Just `string` and/or `number` also match.\n\t *\n\t * @remarks This works recursively looking at first elements when not\n\t * `string` or `number`. `first` will just be a single character if\n\t * not $\\{string\\} or $\\{number\\}.\n\t *\n\t * @system\n\t */\n\texport type IfVariableStringOrNumber<T, IfVariable, IfLiteral> = `${string}` extends T\n\t\t? IfVariable\n\t\t: number extends T\n\t\t\t? IfVariable\n\t\t\t: T extends `${infer first}${infer rest}`\n\t\t\t\t? string extends first\n\t\t\t\t\t? IfVariable\n\t\t\t\t\t: `${number}` extends first\n\t\t\t\t\t\t? IfVariable\n\t\t\t\t\t\t: IfVariableStringOrNumber<rest, IfVariable, IfLiteral>\n\t\t\t\t: IfLiteral;\n\n\t/**\n\t * Essentially a check for a non-fixed number or string OR a branded key.\n\t *\n\t * @remarks There is no known mechanism to determine the primitive from a\n\t * generic tagged (branded) primitive, such as `X$\\{string\\}` & \\{ foo: \"bar\" \\}.\n\t * There appears to be little use for a branded literal key -- at runtime\n\t * there is no brand; so, two of the same literal with different brands would\n\t * collide. Thus any branded key can usually be considered indexed.\n\t *\n\t * @system\n\t */\n\texport type IfIndexOrBrandedKey<\n\t\tT extends keyof AnyRecord,\n\t\tIfIndexOrBranded,\n\t\tOtherwise,\n\t> = T extends object\n\t\t? /* branded string or number */ IfIndexOrBranded\n\t\t: /* => check for variable */ IfVariableStringOrNumber<T, IfIndexOrBranded, Otherwise>;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns `true` if identical and `false` otherwise.\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IsSameType<X, Y> = IfSameType<X, Y, true, false>;\n\n\t/**\n\t * Checks that type is exactly `object`.\n\t *\n\t * @system\n\t */\n\texport type IsExactlyObject<T extends object> = IsSameType<T, object>;\n\n\t/**\n\t * Any Record type.\n\t *\n\t * @system\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- `any` for property types is required to avoid \"Index signature for type 'string' is missing in type\" in some outside `FlattenIntersection` uses.\n\texport type AnyRecord = Record<keyof any, any>;\n\n\t/**\n\t * Creates a simple object type from an intersection of multiple.\n\t * @privateRemarks\n\t * `T extends AnyRecord` within the implementation encourages tsc to process\n\t * intersections within unions.\n\t *\n\t * @system\n\t */\n\texport type FlattenIntersection<T extends AnyRecord> = T extends AnyRecord\n\t\t? {\n\t\t\t\t[K in keyof T]: T[K];\n\t\t\t}\n\t\t: T;\n\n\t/**\n\t * Convenience constraint for any OpaqueJson* type.\n\t *\n\t * @remarks\n\t * Use in extends check: `T extends AnyOpaqueJsonType`\n\t *\n\t * @system\n\t */\n\texport type AnyOpaqueJsonType =\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t\t| OpaqueJsonSerializable<unknown, any, unknown>\n\t\t| OpaqueJsonDeserialized<unknown, any, unknown>;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Extracts Function portion from an intersection (&) type returning\n\t * the extracted portion in the `function` property or `unknown` if\n\t * no function is found.\n\t * The returned `classification` property has one of three values:\n\t * - \"no Function\" if the type is not a function.\n\t * - \"exactly Function\" if the type is exactly a function.\n\t * - \"Function and more\" if the type is a function and has other properties.\n\t *\n\t * @system\n\t */\n\texport type ExtractFunctionFromIntersection<T extends object> = (T extends new (\n\t\t...args: infer A\n\t) => infer R\n\t\t? new (\n\t\t\t\t...args: A\n\t\t\t) => R\n\t\t: unknown) &\n\t\t(T extends (...args: infer A) => infer R\n\t\t\t? (...args: A) => R\n\t\t\t: unknown) extends infer Functional\n\t\t? {\n\t\t\t\tclassification: unknown extends Functional\n\t\t\t\t\t? \"no Function\"\n\t\t\t\t\t: Functional extends Required<T>\n\t\t\t\t\t\t? \"exactly Function\"\n\t\t\t\t\t\t: \"Function and more\";\n\t\t\t\tfunction: Functional;\n\t\t\t}\n\t\t: never;\n\n\t/**\n\t * Returns `Filtered` & any Function intersection from `Original`.\n\t * If `Original` is exactly a Function, then `Filtered` is left out\n\t * under the assumption that it is not useful/applicable.\n\t *\n\t * @system\n\t */\n\texport type FilterPreservingFunction<\n\t\tOriginal extends object,\n\t\tFiltered,\n\t> = ExtractFunctionFromIntersection<Original> extends {\n\t\tclassification: infer TClassification;\n\t\tfunction: infer TFunction;\n\t}\n\t\t? TClassification extends \"exactly Function\"\n\t\t\t? TFunction\n\t\t\t: TFunction & Filtered\n\t\t: never;\n\n\t/**\n\t * Replaces any instance where a type T recurses into itself or a portion of\n\t * itself with TRecursionMarker.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam TRecursionMarker - Replacement marker type.\n\t * @typeParam Controls - Allowances are preserved as-is.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @remarks\n\t * Filtering applied to class instances with non-public properties will not\n\t * preserve the class instance unless those classes are known and listed as\n\t * allowances via `Controls`.\n\t *\n\t * @privateRemarks\n\t * This implementation handles functions including function with properties.\n\t * There are no known cases where replacing recursion under such types make\n\t * a difference. Either the function (whole type) is allowed by the Json\n\t * filters or function is not allowed at all.\n\t * If the function portion is found to be problematic later, then could use\n\t * `T extends Function ? T : ...` to ignore function objects.\n\t *\n\t * @system\n\t */\n\texport type ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tTRecursionMarker,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for recursion */\n\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion => use replacement */ TRecursionMarker\n\t\t: /* force union separation hereafter */ T extends infer _\n\t\t\t? /* test for recursion among union elements */\n\t\t\t\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? TRecursionMarker\n\t\t\t\t: /* test for general allowance */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* allowed extension type => */ T\n\t\t\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact allowed type => */ T\n\t\t\t\t\t\t: T extends object\n\t\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tTRecursionMarker,\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* non-object => T as is */ T\n\t\t\t: never;\n\n\t/**\n\t * Replaces any instances of \"allowed\" types and recursion within with `never`.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam Controls - Allowances to replace.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @system\n\t */\n\texport type ReplaceAllowancesAndRecursionWithNever<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for exact recursion first */ IfExactTypeInTuple<\n\t\tT,\n\t\tTAncestorTypes,\n\t\ttrue,\n\t\t\"no match\"\n\t> extends true\n\t\t? /* recursion => */ never\n\t\t: /* test for general allowance (also forces union separation) */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t? /* allowed extension type => */ never\n\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact allowed type => */ never\n\t\t\t\t: /* test for recursion among union elements */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* recursion => */ never\n\t\t\t\t\t: T extends object\n\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceAllowancesAndRecursionWithNever<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* non-object => T as is */ T;\n\n\t/**\n\t * Test for non-public properties (which can only exist on class instance types).\n\t *\n\t * Returns `HasNonPublic` if `T` deeply may contain a private or protected field\n\t * and `OnlyPublics` otherwise.\n\t *\n\t * @remarks\n\t * Compare original (unprocessed) to filtered case that has `never` where\n\t * recursing or where allowed exception types are used.\n\t *\n\t * Note that this a test of the type and not the actual data. So, if an\n\t * interface is given as `T` where implemented by a class, any private or\n\t * protected fields within the class will not be detected.\n\t *\n\t * @system\n\t */\n\texport type IfNonPublicProperties<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tHasNonPublic = never,\n\t\tOnlyPublics = unknown,\n\t> = ReplaceAllowancesAndRecursionWithNever<T, Controls> extends T\n\t\t? OnlyPublics\n\t\t: HasNonPublic;\n\n\t/**\n\t * Union of all types in a tuple.\n\t *\n\t * @system\n\t */\n\texport type TupleToUnion<T extends unknown[]> = T[number];\n\n\t// #region JsonSerializable implementation\n\n\t/**\n\t * Outer implementation of {@link JsonSerializable} handling meta cases\n\t * like classes (with non-public properties).\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls> & {\n\t\t\t/**\n\t\t\t * See {@link JsonSerializableOptions} for meaning and expected use.\n\t\t\t */\n\t\t\tIgnoreInaccessibleMembers?: \"ignore-inaccessible-members\";\n\t\t},\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute type could be extracted to helper type, but is kept explicit here\n\t\t// to make JsonTypeWith and OpaqueJsonSerializable show explicitly in results for\n\t\t// users, rather than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute:\n\t\t\t| JsonTypeWith<\n\t\t\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t\t\t: never)\n\t\t\t\t\t| (Options extends { AllowExtensionOf: unknown }\n\t\t\t\t\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t: never)\n\t\t\t >\n\t\t\t| OpaqueJsonSerializable<\n\t\t\t\t\tunknown,\n\t\t\t\t\tOptions extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [],\n\t\t\t\t\tOptions extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never\n\t\t\t >;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy FilterControlsWithSubstitution, but Typescript wants a check */\n\t\t\tControls extends FilterControlsWithSubstitution\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: Options extends { IgnoreInaccessibleMembers: \"ignore-inaccessible-members\" }\n\t\t\t\t\t? JsonSerializableFilter<T, Controls, TAncestorTypes, TNextAncestor>\n\t\t\t\t\t: /* test for non-public properties (class instance type) */\n\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in primitives that may be branded to ignore intersection classes\n\t\t\t\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t? /* hidden props => test if it is array properties that are the problem */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonSerializableImpl<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: /* test for potentially branded primitive (intersection with a supported primitive) */\n\t\t\t\t\t\t\t\tT extends boolean | number | string\n\t\t\t\t\t\t\t\t? /* assume intersection is branding and allow as-is => */ T\n\t\t\t\t\t\t\t\t: /* not array => error */ SerializationErrorPerNonPublicProperties\n\t\t\t\t\t\t: /* no hidden properties => apply filtering => */ JsonSerializableFilter<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\tTNextAncestor\n\t\t\t\t\t\t\t>\n\t\t\t: never /* FilterControlsWithSubstitution assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonSerializable}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} and {@link OpaqueJsonDeserialized} instances\n\t * are limited to `Controls` given context supports.\n\t * `T` from the original Opaque type is preserved. In the case that this now\n\t * produces an improper type such as a `bigint` being let through that is no\n\t * longer supported, then the variance of `Controls` is expected to raise\n\t * the incompatibility error.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableOpaqueAllowances<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControlsWithSubstitution,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t/* infer underlying data type */ T extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? T extends OpaqueJsonSerializable<TData, any, unknown> &\n\t\t\t\tOpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]> &\n\t\t\t\t\tOpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t: T extends OpaqueJsonSerializable<TData, any, unknown>\n\t\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t\t: T extends OpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t\t\t? OpaqueJsonDeserialized<\n\t\t\t\t\t\t\tTData,\n\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t>\n\t\t\t\t\t: \"internal error: failed to determine OpaqueJson* type\"\n\t\t: never;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Helper for {@link JsonSerializableFilter} to determine if a property may\n\t * be `undefined` and selects from options for result.\n\t * Since `unknown` is a superset of `undefined`, it is given a special case.\n\t * Additionally since index signatures are inherently optional, `unknown` typed\n\t * values are treated as not undefined (`Result[\"Otherwise\"]`).\n\t *\n\t * @system\n\t */\n\texport type IfPossiblyUndefinedProperty<\n\t\tTKey extends keyof AnyRecord,\n\t\tTValue,\n\t\tResult extends {\n\t\t\tIfPossiblyUndefined: unknown;\n\t\t\tIfUnknownNonIndexed: unknown;\n\t\t\tOtherwise: unknown;\n\t\t},\n\t> = undefined extends TValue\n\t\t? unknown extends TValue\n\t\t\t? IfIndexOrBrandedKey<TKey, Result[\"Otherwise\"], Result[\"IfUnknownNonIndexed\"]>\n\t\t\t: Result[\"IfPossiblyUndefined\"]\n\t\t: Result[\"Otherwise\"];\n\n\t/**\n\t * Core implementation of {@link JsonSerializable}.\n\t *\n\t * @privateRemarks\n\t * Filtering through a single layer of recursion is all that is required\n\t * when using in prescribed filter scenario.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableFilter<\n\t\tT,\n\t\tControls extends FilterControlsWithSubstitution,\n\t\tTAncestorTypes extends unknown[],\n\t\tTNextAncestor = T,\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for recursion */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact recursion; stop here => */ T\n\t\t\t\t: /* test for JSON Encodable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t\t| null\n\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t\t: /* test for exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/ban-types\n\t\t\t\t\t\t\t/* test for not a function */ Extract<T, Function> extends never\n\t\t\t\t\t\t\t? /* not a function => test for object */ T extends object\n\t\t\t\t\t\t\t\t? /* object => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForSerializableArrayItem<\n\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\t\t\t\t\tJsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t\t? /* `object` => */ NonNullJsonObjectWith<\n\t\t\t\t\t\t\t\t\t\t\t\tTupleToUnion<Controls[\"AllowExactly\"]> | Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t\t: /* test for OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonSerializableOpaqueAllowances<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* required properties are recursed and may not have undefined values. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as RequiredNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]-?: IfPossiblyUndefinedProperty<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfPossiblyUndefined: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `undefined` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfUnknownNonIndexed: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `unknown` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tOtherwise: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* optional properties are recursed and, when exactOptionalPropertyTypes is\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t false, are allowed to preserve undefined value type. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as OptionalNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* symbol properties are rejected */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T & symbol]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t: /* not an object => */ never\n\t\t\t\t\t\t\t: /* function => */ never;\n\n\t// #endregion\n\n\t/**\n\t * Sentinel type for use when marking points of recursion (in a recursive type).\n\t * Type is expected to be unique, though no lengths are taken to ensure that.\n\t *\n\t * @system\n\t */\n\texport interface RecursionMarker {\n\t\t[RecursionMarkerSymbol]: typeof RecursionMarkerSymbol;\n\t}\n\n\t// #region JsonDeserialized implementation\n\n\t/**\n\t * Outer implementation of {@link JsonDeserialized} handling meta cases\n\t * like recursive types.\n\t *\n\t * @remarks\n\t * If no modification is needed (`T` is exactly deserializable), `T` will\n\t * be the result.\n\t *\n\t * Upon recursion with `T` that requires modification, `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing.\n\t * Caller will need to unwrap the type to continue processing.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls>,\n\t\tTypeUnderRecursion extends boolean = false,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute types could be extracted to helper type, but are kept explicit here\n\t\t// to make JsonTypeWith/NonNullJsonObjectWith show explicitly in results for users, rather\n\t\t// than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute: JsonTypeWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tDegenerateNonNullObjectSubstitute: NonNullJsonObjectWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tRecursionMarkerAllowed: never;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy DeserializedFilterControls, but Typescript wants a check */\n\t\t\tControls extends DeserializedFilterControls\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tRecursionMarker,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t// Also preserve OpaqueJson* types\n\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t> extends infer TNoRecursionAndOnlyPublics\n\t\t\t\t\t? /* test for no change from filtered type */ IsSameType<\n\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\tJsonDeserializedFilter<\n\t\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf: Controls[\"AllowExtensionOf\"];\n\t\t\t\t\t\t\t\t\tDegenerateSubstitute: Controls[\"DegenerateSubstitute\"];\n\t\t\t\t\t\t\t\t\tDegenerateNonNullObjectSubstitute: Controls[\"DegenerateNonNullObjectSubstitute\"];\n\t\t\t\t\t\t\t\t\tRecursionMarkerAllowed: RecursionMarker;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* same (no filtering needed) => test for non-public\n\t\t\t\t\t\t properties (class instance type) */\n\t\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t\t\t\t// primitives as JsonDeserializedFilter will allow them as\n\t\t\t\t\t\t\t\t// extensions of the primitives. Should there be a need to\n\t\t\t\t\t\t\t\t// explicitly allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t\t? /* hidden props => apply filtering to avoid retaining\n\t\t\t\t\t\t\t exact class except for any classes in allowances =>\n\t\t\t\t\t\t\t\t test for known recursion */\n\t\t\t\t\t\t\t\tTypeUnderRecursion extends false\n\t\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* no hidden properties => deserialized T is just T */\n\t\t\t\t\t\t\t\tT\n\t\t\t\t\t\t: /* filtering is needed => test for known recursion */ TypeUnderRecursion extends false\n\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t: /* unreachable else for infer */ never\n\t\t\t: never /* DeserializedFilterControls assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.JsonDeserializedFilter} up until\n\t * `T` is found to be a match of an ancestor type. At that point `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing, if\n\t * modification is needed. Caller will need to unwrap the type to continue processing.\n\t * If no modification is needed, then `T` will be the result.\n\t *\n\t * @privateRemarks Exact recursion pattern employed should allow shortcut\n\t * test to return `OpaqueJsonDeserialized<T>` from here when the exact\n\t * recursion match is the first ancestor type in tuple as it must have been\n\t * processed and found to need modification.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedRecursion<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTAncestorTypes extends object[],\n\t> = IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion found => reprocess that recursive type directly to avoid\n\t\t any collateral damage from ancestor type that required modification.\n\t\t\t Further recursion will not happen during processing. Either:\n\t\t\t - the type requires modification and the `TypeUnderRecursion=true`\n\t\t\t arg will result in `OpaqueJsonDeserialized<T>` wrapper OR\n\t\t\t - no change is needed from this point and `T` will result. */\n\t\t\tJsonDeserializedImpl<T, Controls, true>\n\t\t: T extends object\n\t\t\t? IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? JsonDeserializedImpl<T, Controls, true>\n\t\t\t\t: /* no recursion yet detected => */ JsonDeserializedFilter<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls,\n\t\t\t\t\t\t[...TAncestorTypes, T]\n\t\t\t\t\t>\n\t\t\t: /* not an object (no recursion) => */ JsonDeserializedFilter<\n\t\t\t\t\tT,\n\t\t\t\t\tControls,\n\t\t\t\t\tTAncestorTypes\n\t\t\t\t>;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonDeserialized}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} instances are converted to {@link OpaqueJsonDeserialized}.\n\t * The `AllowExactly` and `AllowExtensionOf` properties are set to match the given `Controls`.\n\t * The data type is kept exactly as-is to avoid processing in generic contexts that can't\n\t * produce a meaningful result. The data type should always be filtered through\n\t * {@link JsonDeserialized} when {@link OpaqueJsonDeserialized} is cracked open. So, really\n\t * the filtering is just deferred.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedOpaqueConversion<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControls,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\tT extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? OpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t: \"internal error: failed to determine OpaqueJson* type\";\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Core implementation of {@link JsonDeserialized}.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedFilter<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\t// Always start with object portion of self as ancestor. Filtering will\n\t\t// not apply past recursion (nested occurrence of this).\n\t\tTAncestorTypes extends object[] = [Extract<T, object>],\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for deserializable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t: /* test for given exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"not found\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t: /* test for object */ T extends object\n\t\t\t\t\t\t? /* object => */ ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t? /* exactly function => */ never\n\t\t\t\t\t\t\t: /* not exactly a function (Function portion, if any, is omitted) */\n\t\t\t\t\t\t\t\t/* => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForDeserializedArrayItem<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\tJsonDeserializedRecursion<T[K], Controls, TAncestorTypes>\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t? /* `object` => */ Controls[\"DegenerateNonNullObjectSubstitute\"]\n\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t: /* test for matching OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonDeserializedOpaqueConversion<T, Controls>\n\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with symbol keys or wholly unsupported values are removed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with defined values are recursed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolWithDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* literal properties that may have undefined values are optional */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* not an object => */ never;\n\n\t// #endregion\n\n\t// #region *Readonly implementations\n\n\t/**\n\t * Recursion limit is the count of `+` that prefix it when string.\n\t *\n\t * @system\n\t */\n\texport type RecursionLimit = `+${string}` | 0;\n\n\t/**\n\t * If `T` is a `Map<K,V>` or `ReadonlyMap<K,V>`, returns `ReadonlyMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlyMap<infer K, infer V>\n\t\t? Map<K, V> extends DeepenedGenerics\n\t\t\t? ReadonlyMap<\n\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t>\n\t\t\t: ReadonlyMap<K, V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Set<TSet>` or `ReadonlySet<TSet>`, returns `ReadonlySet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlySet<infer V>\n\t\t? Set<V> extends DeepenedGenerics\n\t\t\t? ReadonlySet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: ReadonlySet<V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `IFluidHandle<THandle>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `THandle` generic.\n\t * `Else` is returned if not an `IFluidHandle`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInFluidHandleIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Readonly<IFluidHandle<infer V>>\n\t\t? IFluidHandle<V> extends DeepenedGenerics\n\t\t\t? Readonly<IFluidHandle<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>>\n\t\t\t: Readonly<T>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Promise<TPromise>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `TPromise` generic.\n\t * `Else` is returned if not a `Promise`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInPromiseIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Promise<infer V>\n\t\t? Promise<V> extends DeepenedGenerics\n\t\t\t? Promise<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: T\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakMap<K,V>`, returns immutable `WeakMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakMap<infer K, infer V>, \"delete\" | \"set\">\n\t\t? WeakMap<K, V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakMap<\n\t\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t\t>,\n\t\t\t\t\t\"delete\" | \"set\"\n\t\t\t\t>\n\t\t\t: Omit<WeakMap<K, V>, \"delete\" | \"set\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakSet<TSet>`, returns immutable `WeakSet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic weak set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakSet<infer V>, \"add\" | \"delete\">\n\t\t? WeakSet<V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakSet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>,\n\t\t\t\t\t\"add\" | \"delete\"\n\t\t\t\t>\n\t\t\t: Omit<WeakSet<V>, \"add\" | \"delete\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a {@link ReadonlySupportedGenerics}, `T` is returned as\n\t * its immutable version, and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `T`s generics.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInGenerics<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics,\n\t\tNoDepthOrRecurseLimit,\n\t\tDeepenReadonlyInSetIfEnabled<\n\t\t\tT,\n\t\t\tDeepenedGenerics,\n\t\t\tNoDepthOrRecurseLimit,\n\t\t\tDeepenReadonlyInWeakMapIfEnabled<\n\t\t\t\tT,\n\t\t\t\tDeepenedGenerics,\n\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\tDeepenReadonlyInWeakSetIfEnabled<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\tDeepenReadonlyInPromiseIfEnabled<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\tDeepenReadonlyInFluidHandleIfEnabled<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\t\tElse\n\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t>\n\t>;\n\n\t/**\n\t * Returns an `ErasedType` or \"branded\" primitive type as-is, or `Else` if not.\n\t * @typeParam T - Type to test.\n\t * @typeParam Else - Type to return if not `ErasedType` or \"branded\" primitive.\n\t *\n\t * @system\n\t */\n\texport type PreserveErasedTypeOrBrandedPrimitive<\n\t\tT extends object,\n\t\tElse,\n\t> = /* Test for erased type */ T extends ErasedType<infer _>\n\t\t? /* erased type => keep as-is */ T\n\t\t: /* Test for branded primitive */ T extends infer Brand &\n\t\t\t\t\t(boolean | number | string | symbol | bigint)\n\t\t\t? // Should just return T here, but TypeScript appears to produce `never` when doing so.\n\t\t\t\t// Workaround by inferring the Primitive type and returning intersection with B.\n\t\t\t\tT extends Brand & infer Primitive\n\t\t\t\t? /* [potentially] branded type => \"as-is\" */ Primitive & Brand\n\t\t\t\t: /* Should never be reached */ T\n\t\t\t: Else;\n\n\t/**\n\t * De-multiplexing implementation of {@link DeepReadonly} and {@link ShallowReadonly}\n\t * selecting behavior based on `NoDepthOrRecurseLimit`.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant. Its importance is that other utilities common to\n\t * readonly transformation may use `NoDepthOrRecurseLimit` to return the the\n\t * same processing algorithm.\n\t *\n\t * @system\n\t */\n\texport type ReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t> = /* test for no depth */ NoDepthOrRecurseLimit extends \"Shallow\"\n\t\t? /* no depth => */ ShallowReadonlyImpl<T, DeepenedGenerics>\n\t\t: /* test for no limit */ NoDepthOrRecurseLimit extends \"NoLimit\"\n\t\t\t? /* no limit => */ DeepReadonlyRecursingInfinitely<T, DeepenedGenerics>\n\t\t\t: /* limited */ DeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>;\n\n\t// #region ShallowReadonly implementation\n\n\t/**\n\t * Outer implementation of {@link ShallowReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility can be reentrant when generics are deepened.\n\t *\n\t * @system\n\t */\n\texport type ShallowReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\"Shallow\",\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<T, /* basic type => */ Readonly<T>>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\n\t/**\n\t * Outer implementation of {@link DeepReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `RecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends DeepReadonlyRecursionLimit,\n\t> = ReadonlyImpl<T, DeepenedGenerics, RecurseLimit>;\n\n\t// #region DeepReadonly infinite recursion implementation\n\n\t/**\n\t * Simple implementation of {@link DeepReadonly} that may handle limited recursive types.\n\t * In unhandled cases, TypeScript will produce:\n\t * ts(2589): Type instantiation is excessively deep and possibly infinite.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursingInfinitely<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\t// test for array of known recursive type: JsonTypeWith\n\t\t\t\tT extends readonly ReadonlyJsonTypeWith<infer Alternates>[]\n\t\t\t\t\t? // Make sure this is exactly that case (many arrays will extend JsonTypeWith)\n\t\t\t\t\t\t// Note that `true extends IfExactTypeInTuple` is used over\n\t\t\t\t\t\t// if-else form as the else branch would be evaluated as input to\n\t\t\t\t\t\t// `IfExactTypeInTuple` and that could lead to infinite recursion.\n\t\t\t\t\t\ttrue extends IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[JsonTypeWith<Alternates>[], readonly ReadonlyJsonTypeWith<Alternates>[]]\n\t\t\t\t\t\t>\n\t\t\t\t\t\t? readonly ReadonlyJsonTypeWith<\n\t\t\t\t\t\t\t\tDeepReadonlyRecursingInfinitely<Alternates, DeepenedGenerics>\n\t\t\t\t\t\t\t>[]\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: /* not JSON array => */ DeepenReadonlyInGenerics<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\"NoLimit\",\n\t\t\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #region DeepReadonly limited recursion implementation\n\n\t/**\n\t * Core implementation of {@link DeepReadonly} handling meta cases\n\t * like recursive types a limited number of times.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `NoDepthOrRecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyLimitingRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends RecursionLimit,\n\t> = /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tRecursionMarker,\n\t\t{ AllowExactly: []; AllowExtensionOf: never }\n\t> extends infer TNoRecursionAndOnlyPublics\n\t\t? /* test for no change from altered type (excluding non-publics) */ IsSameType<\n\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\tDeepReadonlyWorker<TNoRecursionAndOnlyPublics, DeepenedGenerics, 0>\n\t\t\t> extends true\n\t\t\t? /* same (no filtering needed) => test for non-public properties (class instance type) */\n\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\tT,\n\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t// primitives as DeepReadonlyWorker will allow them as\n\t\t\t\t\t// extensions of the primitives. Should there need a need to\n\t\t\t\t\t// explicit allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t{ AllowExactly: []; AllowExtensionOf: never },\n\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\"only publics\"\n\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t? /* hidden props => apply filtering => */\n\t\t\t\t\tDeepReadonlyWorker<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t\t>\n\t\t\t\t: /* no hidden properties => readonly T is just T */\n\t\t\t\t\tT\n\t\t\t: /* filtering is needed => */ DeepReadonlyWorker<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>\n\t\t: /* unreachable else for infer */ never;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.DeepReadonlyWorker} up to `RecurseLimit` times.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = T extends TAncestorTypes\n\t\t? RecurseLimit extends `+${infer RecursionRemainder}`\n\t\t\t? /* Now that specific recursion is found, process that recursive type\n\t\t\t directly to avoid any collateral damage from ancestor type that\n\t\t\t required modification. */\n\t\t\t\tDeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecursionRemainder extends RecursionLimit ? RecursionRemainder : 0\n\t\t\t\t>\n\t\t\t: T\n\t\t: DeepReadonlyWorker<T, DeepenedGenerics, RecurseLimit, TAncestorTypes | T>;\n\n\t/**\n\t * Core implementation of {@link InternalUtilityTypes.DeepReadonlyLimitingRecursion}.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyWorker<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = /* test for object */ T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecurseLimit,\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursion<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\tRecurseLimit,\n\t\t\t\t\t\t\t\tTAncestorTypes\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #endregion\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exposedInternalUtilityTypes.js","sourceRoot":"","sources":["../src/exposedInternalUtilityTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH;;GAEG;AACH,MAAM,qBAAqB,GAAkB,MAAM,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @rushstack/no-new-null */\n\nimport type { ErasedType } from \"./erasedType.js\";\nimport type { IFluidHandle } from \"./handles.js\";\nimport type {\n\tSerializationErrorPerNonPublicProperties,\n\tSerializationErrorPerUndefinedArrayElement,\n} from \"./jsonSerializationErrors.js\";\nimport type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from \"./jsonType.js\";\nimport type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from \"./opaqueJson.js\";\n\n/**\n * Unique symbol for recursion meta-typing.\n */\nconst RecursionMarkerSymbol: unique symbol = Symbol(\"recursion here\");\n\n/**\n * Union of types that {@link DeepReadonly} and {@link ShallowReadonly}\n * recognize to generate immutable form and optionally can alter their\n * type parameters.\n *\n * @privateRemarks\n * WeakRef should be added when lib is updated to ES2021 or later.\n *\n * @beta\n */\nexport type ReadonlySupportedGenerics =\n\t| IFluidHandle\n\t| Map<unknown, unknown>\n\t| Promise<unknown>\n\t| Set<unknown>\n\t| WeakMap<object, unknown>\n\t| WeakSet<object>;\n\n/**\n * Limit on processing recursive types.\n * Use of `\"NoLimit\"` may result in error:\n * \"ts(2589): Type instantiation is excessively deep and possibly infinite\".\n * In such cases, use string literal with some prefix series of `+`\n * characters. The length of `+` character sequence indicates the recursion\n * depth limit when a recursive type is found. Use of `0` will stop applying\n * `DeepReadonly` at the first point recursion is detected.\n *\n * @beta\n * @system\n */\nexport type DeepReadonlyRecursionLimit = \"NoLimit\" | 0 | `+${string}`;\n\n/**\n * Collection of utility types that are not intended to be used/imported\n * directly outside of this package.\n *\n * @privateRemarks\n * There are ony three intentional exports from this module:\n * - {@link InternalUtilityTypes.IfSameType | IfSameType}\n * - {@link InternalUtilityTypes.JsonDeserializedImpl | JsonDeserializedImpl }\n * - {@link InternalUtilityTypes.JsonSerializableImpl | JsonSerializableImpl }\n *\n * api-extractor will allow `export` to be removed from others but generates\n * api-report a little oddly with a rogue `{};` floating at end of namespace\n * in api.md file. It will promote all of the support types to appear as\n * exported anyway. All in namespace are left exported to avoid api-extractor\n * potentially failing to validate other modules correctly.\n *\n * @beta\n * @system\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace InternalUtilityTypes {\n\t/**\n\t * Meta-type for controlling filtering utilities.\n\t *\n\t * @system\n\t */\n\texport interface FilterControls {\n\t\t/**\n\t\t * Tuple of exact types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Only exact types matching specification will be preserved unaltered.\n\t\t */\n\t\tAllowExactly: unknown[];\n\n\t\t/**\n\t\t * General types that are managed by custom serialization/deserialization\n\t\t * logic (beyond JSON.stringify and JSON.parse without replacers/revivers).\n\t\t * Any type satisfying specification will be preserved unaltered.\n\t\t */\n\t\tAllowExtensionOf: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling filtering utilities that additionally supplies\n\t * a substitute type for degenerate cases.\n\t *\n\t * @system\n\t */\n\tinterface FilterControlsWithSubstitution extends FilterControls {\n\t\t/**\n\t\t * Type to use for degenerate cases like `unknown` or `any`.\n\t\t * Typically this will be `JsonTypeWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateSubstitute: unknown;\n\t}\n\n\t/**\n\t * Meta-type for controlling deserialized filtering utilities.\n\t *\n\t * @system\n\t */\n\tinterface DeserializedFilterControls extends FilterControlsWithSubstitution {\n\t\t/**\n\t\t * Type to use for degenerate `object` case.\n\t\t * Typically this will be `NonNullJsonObjectWith<TupleToUnion<AllowExactly> | AllowExtensionOf>`.\n\t\t */\n\t\tDegenerateNonNullObjectSubstitute: unknown;\n\n\t\t/**\n\t\t * Either `RecursionMarker` when filtering after recursion has been replace or `never`\n\t\t */\n\t\tRecursionMarkerAllowed: unknown; // Can be RecursionMarker ?\n\t}\n\n\t/**\n\t * Returns non-symbol keys for optional properties of an object type.\n\t * This excludes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as OptionalNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type OptionalNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? never : K;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol keys for required properties of an object type.\n\t * This includes indexed properties that are inherently _optional_.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as RequiredNonSymbolKeysOf<T, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type RequiredNonSymbolKeysOf<\n\t\tT extends object,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: T extends Record<K, T[K]> ? K : never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns Result.WhenSomethingDeserializable if T is sometimes at least a\n\t * partially deserializable type, otherwise Result.WhenNeverDeserializable.\n\t * Fully not deserializable (bigints, symbols, undefined and functions without\n\t * other properties less overlap with T*Exception) produce Result.WhenNeverDeserializable.\n\t * An object would have a defined result even if parts of its content are\n\t * not deserializable.\n\t *\n\t * @param Result - Result type with two properties. One property must always\n\t * be `never` as `T` maybe a union of never deserializable and at least\n\t * partially deserializable types and the result is a union of Result.*.\n\t *\n\t * @privateRemarks\n\t * If `Result.WhenSomethingDeserializable` was `true` and\n\t * `Result.WhenNeverDeserializable` was `false`, then the return type\n\t * for type `T` would be `boolean` for a sometimes deserializable type.\n\t *\n\t * @system\n\t */\n\texport type TestDeserializabilityOf<\n\t\tT,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tResult extends\n\t\t\t| { WhenSomethingDeserializable: unknown; WhenNeverDeserializable: never }\n\t\t\t| { WhenSomethingDeserializable: never; WhenNeverDeserializable: unknown },\n\t> = /* ensure working with more than never */ T extends never\n\t\t? /* never => */ Result[\"WhenNeverDeserializable\"]\n\t\t: /* check for extends exception */ T extends TExtendsException\n\t\t\t? /* extends exception => */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t: /* no extends exception => check for exact exception */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTExactExceptions,\n\t\t\t\t\t/* exact exception => */ Result[\"WhenSomethingDeserializable\"],\n\t\t\t\t\t/* no exception => check for only non-serializable value types */ T extends\n\t\t\t\t\t\t| bigint\n\t\t\t\t\t\t| symbol\n\t\t\t\t\t\t| undefined\n\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t? /* not serializable => */ Result[\"WhenNeverDeserializable\"]\n\t\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t\t\t\t: /* at least partially serializable */ Result[\"WhenSomethingDeserializable\"]\n\t\t\t\t>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact `U`s from `T`\n\t * rather than any type that extends `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactly<T, U> = IfSameType<T, U, never, T>;\n\n\t/**\n\t * Similar to `Exclude` but only excludes exact members of `U` from `T`\n\t * rather than any type that extends members of `U`.\n\t *\n\t * @system\n\t */\n\texport type ExcludeExactlyInTuple<T, TupleOfU extends unknown[]> = IfExactTypeInTuple<\n\t\tT,\n\t\tTupleOfU,\n\t\tnever,\n\t\tT\n\t>;\n\n\t/**\n\t * Similar to `Omit` but operates on tuples.\n\t * Removes elements of `Tuple` that extend `U`.\n\t *\n\t * @system\n\t */\n\texport type OmitFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitFromTuple<Rest, U, First extends U ? Accumulated : [...Accumulated, First]>\n\t\t: Accumulated;\n\n\t/**\n\t * Similar to `OmitFromTuple` but removes only exact matches of U.\n\t * Removes elements of `Tuple` that are exactly `U`.\n\t *\n\t * @remarks If `U` is a union, then only exactly matching union elements of `Tuple` are removed.\n\t * @system\n\t */\n\texport type OmitExactlyFromTuple<\n\t\tTuple extends unknown[],\n\t\tU,\n\t\tAccumulated extends unknown[] = [],\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? OmitExactlyFromTuple<Rest, U, IfSameType<First, U, Accumulated, [...Accumulated, First]>>\n\t\t: Accumulated;\n\n\t/**\n\t * Returns non-symbol keys for defined, (likely) serializable properties of an\n\t * object type. Literal keys with fully unsupported properties (undefined, symbol,\n\t * and bigint) and sometimes unsupported (functions) are excluded. An exception to\n\t * that is when there are supported types in union with just bigint. Indexed keys\n\t * are only excluded when there are no supported properties.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolWithDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: /* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\tExcludeExactlyInTuple<\n\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t? IfSameType<\n\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\tunknown,\n\t\t\t\t\t\t/* value might not be supported => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t>,\n\t\t\t\t\t\t/* extract types that might lead to missing property */ Extract<\n\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t/* types that might lead to missing property, except `bigint` */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t\t? /* all types are supported plus possibly `bigint` => */\n\t\t\t\t\t\t\t\t/* check for only `bigint` remaining */ IfSameType<\n\t\t\t\t\t\t\t\t\tPossibleTypeLessAllowed,\n\t\t\t\t\t\t\t\t\tbigint,\n\t\t\t\t\t\t\t\t\t/* only `bigint` => nothing supported */ never,\n\t\t\t\t\t\t\t\t\t/* exclusively supported types (and maybe `bigint`) or exactly `never` */\n\t\t\t\t\t\t\t\t\t/* => check for `never` */ T[K] extends never ? never : K\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* value might not be supported => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: /* => check for indexed key */ IfIndexOrBrandedKey<\n\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t/* indexed => allow K */ K,\n\t\t\t\t\t\t\t\t\t\t\t/* literal => exclude K */ never\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: /* => exclude K */ never;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t: never;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Returns non-symbol, literal keys for partially supported properties of an object type.\n\t * Keys with only unsupported properties (undefined, symbol, bigint, and\n\t * functions without other properties) are excluded.\n\t *\n\t * For homomorphic mapping use with `as` to filter. Example:\n\t * `[K in keyof T as NonSymbolWithPossiblyDeserializablePropertyOf<T, [], never, K>]: ...`\n\t *\n\t * @system\n\t */\n\texport type NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\tT extends object,\n\t\tTExactExceptions extends unknown[],\n\t\tTExtendsException,\n\t\tKeys extends keyof T = keyof T,\n\t> = Exclude<\n\t\t{\n\t\t\t[K in Keys]: IfIndexOrBrandedKey<\n\t\t\t\tK,\n\t\t\t\t/* indexed => exclude K */ never,\n\t\t\t\t/* literal => ... */\n\t\t\t\t/* all possible types that aren't already allowed, with the exception of `unknown` */\n\t\t\t\tExcludeExactlyInTuple<\n\t\t\t\t\tExclude<T[K], TExtendsException>,\n\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>\n\t\t\t\t> extends infer PossibleTypeLessAllowed\n\t\t\t\t\t? Extract<\n\t\t\t\t\t\t\tIfSameType<PossibleTypeLessAllowed, unknown, undefined, PossibleTypeLessAllowed>,\n\t\t\t\t\t\t\t/* types that might lead to missing property */\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\tundefined | symbol | Function\n\t\t\t\t\t\t> extends never\n\t\t\t\t\t\t? /* exclusively supported types or exactly `never` */ never\n\t\t\t\t\t\t: /* at least some unsupported type => check for any supported */ TestDeserializabilityOf<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tOmitExactlyFromTuple<TExactExceptions, unknown>,\n\t\t\t\t\t\t\t\tTExtendsException,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tWhenSomethingDeserializable: K;\n\t\t\t\t\t\t\t\t\tWhenNeverDeserializable: never;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t: never\n\t\t\t>;\n\t\t}[Keys],\n\t\tundefined | symbol\n\t> extends infer Result\n\t\t? // Workaround for TypeScript bug/limitation where an alias for a type\n\t\t\t// is not considered the same type when used as an index. This restores\n\t\t\t// the original `Keys` (`keyof T`) type when there is no filtering.\n\t\t\tIfSameType<Keys, Result, Keys, Extract<Result, string | number>>\n\t\t: never;\n\n\t/**\n\t * Filters a type `T` for `undefined` that is not viable in an array (or tuple) that\n\t * must go through JSON serialization.\n\t * If `T` is `undefined`, then error type {@link SerializationErrorPerUndefinedArrayElement}\n\t * is returned with hopes of being informative.\n\t *\n\t * @system\n\t */\n\texport type JsonForSerializableArrayItem<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[],\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined. */\n\t/* These tests are expected to match those in JsonSerializableImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for exact recursion */ IfExactTypeInTuple<\n\t\t\t\t\tT,\n\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t/* recursion; stop here => */ T,\n\t\t\t\t\t/* test for JSON primitive types or given alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t? /* primitive types or alternative => */ T\n\t\t\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* test for undefined possibility */ undefined extends T\n\t\t\t\t\t\t\t\t\t? /* undefined | ... => */ SerializationErrorPerUndefinedArrayElement\n\t\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t\t\t>\n\t\t\t\t>;\n\n\t/**\n\t * Filters a type `T` for types that become null through JSON serialization.\n\t *\n\t * @system\n\t */\n\texport type JsonForDeserializedArrayItem<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTBlessed,\n\t> = /* Some initial filtering must be provided before a test for undefined, symbol, or function. */\n\t/* These tests are expected to match those in JsonDeserializedImpl. */\n\t/* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ TBlessed\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ TBlessed\n\t\t\t: /* test for JSON primitive types or general alternative */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive or replaced types => */ T\n\t\t\t\t: /* test for exact alternative */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t/* exactly replaced => */ T,\n\t\t\t\t\t\t/* test for known types that become null */ T extends undefined | symbol\n\t\t\t\t\t\t\t? /* => */ null\n\t\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\t\tT extends Function\n\t\t\t\t\t\t\t\t? ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t? null\n\t\t\t\t\t\t\t\t\t: null | TBlessed\n\t\t\t\t\t\t\t\t: TBlessed\n\t\t\t\t\t>;\n\n\t/**\n\t * Checks for a type that is simple class of number and string indexed types to numbers and strings.\n\t *\n\t * @system\n\t */\n\texport type IfEnumLike<\n\t\tT extends object,\n\t\tEnumLike = never,\n\t\tNotEnumLike = unknown,\n\t> = T extends readonly (infer _)[]\n\t\t? /* array => */ NotEnumLike\n\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\tT extends Function\n\t\t\t? /* function => */ NotEnumLike\n\t\t\t: T extends {\n\t\t\t\t\t\t// all numerical indices should refer to a string\n\t\t\t\t\t\treadonly [i: number]: string;\n\t\t\t\t\t\t// string indices may be string or number\n\t\t\t\t\t\treadonly [p: string]: number | string;\n\t\t\t\t\t\t// no symbol indices are allowed\n\t\t\t\t\t\treadonly [s: symbol]: never;\n\t\t\t\t\t}\n\t\t\t\t? /* test for a never or any property */ true extends {\n\t\t\t\t\t\t[K in keyof T]: T[K] extends never ? true : never;\n\t\t\t\t\t}[keyof T]\n\t\t\t\t\t? NotEnumLike\n\t\t\t\t\t: EnumLike\n\t\t\t\t: NotEnumLike;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns IfSame if identical and IfDifferent otherwise.\n\t *\n\t * Implementation derived from https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IfSameType<X, Y, IfSame = unknown, IfDifferent = never> = (<T>() => T extends X\n\t\t? 1\n\t\t: 2) extends <T>() => T extends Y ? 1 : 2\n\t\t? IfSame\n\t\t: IfDifferent;\n\n\t/**\n\t * Test for type equality with tuple of other types.\n\t *\n\t * @typeParam T - Type to find in Tuple.\n\t * @typeParam Tuple - Tuple of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @privateRemarks\n\t * Tests for an exact match of `T` in `Tuple[0]`. If not found,\n\t * recurses with the remainder of the tuple.\n\t */\n\texport type IfExactTypeInTuple<\n\t\tT,\n\t\tTuple extends unknown[],\n\t\tIfMatch = unknown,\n\t\tIfNoMatch = never,\n\t> = Tuple extends [infer First, ...infer Rest]\n\t\t? IfSameType<T, First, IfMatch, IfExactTypeInTuple<T, Rest, IfMatch, IfNoMatch>>\n\t\t: IfNoMatch;\n\n\t/**\n\t * Test for type equality with union of other types.\n\t *\n\t * @typeParam T - Type to find in Union. If this is itself a union, then all types must be found in Union.\n\t * @typeParam Union - Union of types to test against.\n\t * @typeParam IfMatch - Type to return if match is found.\n\t * @typeParam IfNoMatch - Type to return if no match is found.\n\t *\n\t * @remarks\n\t * In a recursive context, use {@link InternalUtilityTypes.IfExactTypeInTuple} to manage ancestry.\n\t *\n\t * @privateRemarks\n\t * Perhaps it is a Typescript defect but a simple check that `T` is `never`\n\t * via `T extends never` does not work as expected in this context.\n\t * Workaround using `IfSameType<..., never,...>`.\n\t * @system\n\t */\n\texport type IfExactTypeInUnion<T, Union, IfMatch = unknown, IfNoMatch = never> = IfSameType<\n\t\tT,\n\t\tnever,\n\t\t/* T is never => */ IfSameType<Union, never, IfMatch, IfNoMatch>,\n\t\t/* T is NOT never => */ IfSameType<T, Extract<Union, T>, IfMatch, IfNoMatch>\n\t>;\n\n\t/**\n\t * Check for a template literal that has $\\{string\\} or $\\{number\\}\n\t * in the pattern. Just `string` and/or `number` also match.\n\t *\n\t * @remarks This works recursively looking at first elements when not\n\t * `string` or `number`. `first` will just be a single character if\n\t * not $\\{string\\} or $\\{number\\}.\n\t *\n\t * @system\n\t */\n\texport type IfVariableStringOrNumber<T, IfVariable, IfLiteral> = `${string}` extends T\n\t\t? IfVariable\n\t\t: number extends T\n\t\t\t? IfVariable\n\t\t\t: T extends `${infer first}${infer rest}`\n\t\t\t\t? string extends first\n\t\t\t\t\t? IfVariable\n\t\t\t\t\t: `${number}` extends first\n\t\t\t\t\t\t? IfVariable\n\t\t\t\t\t\t: IfVariableStringOrNumber<rest, IfVariable, IfLiteral>\n\t\t\t\t: IfLiteral;\n\n\t/**\n\t * Essentially a check for a non-fixed number or string OR a branded key.\n\t *\n\t * @remarks There is no known mechanism to determine the primitive from a\n\t * generic tagged (branded) primitive, such as `X$\\{string\\}` & \\{ foo: \"bar\" \\}.\n\t * There appears to be little use for a branded literal key -- at runtime\n\t * there is no brand; so, two of the same literal with different brands would\n\t * collide. Thus any branded key can usually be considered indexed.\n\t *\n\t * @system\n\t */\n\texport type IfIndexOrBrandedKey<\n\t\tT extends keyof AnyRecord,\n\t\tIfIndexOrBranded,\n\t\tOtherwise,\n\t> = T extends object\n\t\t? /* branded string or number */ IfIndexOrBranded\n\t\t: /* => check for variable */ IfVariableStringOrNumber<T, IfIndexOrBranded, Otherwise>;\n\n\t/**\n\t * Test for type equality\n\t *\n\t * @returns `true` if identical and `false` otherwise.\n\t *\n\t * @remarks Use caution when one of the type might be `{}`. That type is\n\t * special and produces unexpected results. This includes variability\n\t * on past usages.\n\t *\n\t * @system\n\t */\n\texport type IsSameType<X, Y> = IfSameType<X, Y, true, false>;\n\n\t/**\n\t * Checks that type is exactly `object`.\n\t *\n\t * @system\n\t */\n\texport type IsExactlyObject<T extends object> = IsSameType<T, object>;\n\n\t/**\n\t * Any Record type.\n\t *\n\t * @system\n\t */\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any -- `any` for property types is required to avoid \"Index signature for type 'string' is missing in type\" in some outside `FlattenIntersection` uses.\n\texport type AnyRecord = Record<keyof any, any>;\n\n\t/**\n\t * Creates a simple object type from an intersection of multiple.\n\t * @privateRemarks\n\t * `T extends AnyRecord` within the implementation encourages tsc to process\n\t * intersections within unions.\n\t *\n\t * @system\n\t */\n\texport type FlattenIntersection<T extends AnyRecord> = T extends AnyRecord\n\t\t? {\n\t\t\t\t[K in keyof T]: T[K];\n\t\t\t}\n\t\t: T;\n\n\t/**\n\t * Convenience constraint for any OpaqueJson* type.\n\t *\n\t * @remarks\n\t * Use in extends check: `T extends AnyOpaqueJsonType`\n\t *\n\t * @system\n\t */\n\texport type AnyOpaqueJsonType =\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t\t| OpaqueJsonSerializable<unknown, any, unknown>\n\t\t| OpaqueJsonDeserialized<unknown, any, unknown>;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Extracts Function portion from an intersection (&) type returning\n\t * the extracted portion in the `function` property or `unknown` if\n\t * no function is found.\n\t * The returned `classification` property has one of three values:\n\t * - \"no Function\" if the type is not a function.\n\t * - \"exactly Function\" if the type is exactly a function.\n\t * - \"Function and more\" if the type is a function and has other properties.\n\t *\n\t * @system\n\t */\n\texport type ExtractFunctionFromIntersection<T extends object> = (T extends new (\n\t\t...args: infer A\n\t) => infer R\n\t\t? new (\n\t\t\t\t...args: A\n\t\t\t) => R\n\t\t: unknown) &\n\t\t(T extends (...args: infer A) => infer R\n\t\t\t? (...args: A) => R\n\t\t\t: unknown) extends infer Functional\n\t\t? {\n\t\t\t\tclassification: unknown extends Functional\n\t\t\t\t\t? \"no Function\"\n\t\t\t\t\t: Functional extends Required<T>\n\t\t\t\t\t\t? \"exactly Function\"\n\t\t\t\t\t\t: \"Function and more\";\n\t\t\t\tfunction: Functional;\n\t\t\t}\n\t\t: never;\n\n\t/**\n\t * Returns `Filtered` & any Function intersection from `Original`.\n\t * If `Original` is exactly a Function, then `Filtered` is left out\n\t * under the assumption that it is not useful/applicable.\n\t *\n\t * @system\n\t */\n\texport type FilterPreservingFunction<\n\t\tOriginal extends object,\n\t\tFiltered,\n\t> = ExtractFunctionFromIntersection<Original> extends {\n\t\tclassification: infer TClassification;\n\t\tfunction: infer TFunction;\n\t}\n\t\t? TClassification extends \"exactly Function\"\n\t\t\t? TFunction\n\t\t\t: TFunction & Filtered\n\t\t: never;\n\n\t/**\n\t * Replaces any instance where a type T recurses into itself or a portion of\n\t * itself with TRecursionMarker.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam TRecursionMarker - Replacement marker type.\n\t * @typeParam Controls - Allowances are preserved as-is.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @remarks\n\t * Filtering applied to class instances with non-public properties will not\n\t * preserve the class instance unless those classes are known and listed as\n\t * allowances via `Controls`.\n\t *\n\t * @privateRemarks\n\t * This implementation handles functions including function with properties.\n\t * There are no known cases where replacing recursion under such types make\n\t * a difference. Either the function (whole type) is allowed by the Json\n\t * filters or function is not allowed at all.\n\t * If the function portion is found to be problematic later, then could use\n\t * `T extends Function ? T : ...` to ignore function objects.\n\t *\n\t * @system\n\t */\n\texport type ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tTRecursionMarker,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for recursion */\n\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion => use replacement */ TRecursionMarker\n\t\t: /* force union separation hereafter */ T extends infer _\n\t\t\t? /* test for recursion among union elements */\n\t\t\t\tIfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? TRecursionMarker\n\t\t\t\t: /* test for general allowance */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* allowed extension type => */ T\n\t\t\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact allowed type => */ T\n\t\t\t\t\t\t: T extends object\n\t\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tTRecursionMarker,\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* non-object => T as is */ T\n\t\t\t: never;\n\n\t/**\n\t * Replaces any instances of \"allowed\" types and recursion within with `never`.\n\t *\n\t * @typeParam T - Type to process.\n\t * @typeParam Controls - Allowances to replace.\n\t * @typeParam TAncestorTypes - Tuple of types that are ancestors of T.\n\t * @typeParam TNextAncestor - Set exactly to T. This is passed separately\n\t * such that T union types remain intact as exact ancestors.\n\t *\n\t * @system\n\t */\n\texport type ReplaceAllowancesAndRecursionWithNever<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* test for exact recursion first */ IfExactTypeInTuple<\n\t\tT,\n\t\tTAncestorTypes,\n\t\ttrue,\n\t\t\"no match\"\n\t> extends true\n\t\t? /* recursion => */ never\n\t\t: /* test for general allowance (also forces union separation) */ T extends Controls[\"AllowExtensionOf\"]\n\t\t\t? /* allowed extension type => */ never\n\t\t\t: /* test for exact allowance */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact allowed type => */ never\n\t\t\t\t: /* test for recursion among union elements */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* recursion => */ never\n\t\t\t\t\t: T extends object\n\t\t\t\t\t\t? FilterPreservingFunction<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t[K in keyof T]: ReplaceAllowancesAndRecursionWithNever<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* non-object => T as is */ T;\n\n\t/**\n\t * Test for non-public properties (which can only exist on class instance types).\n\t *\n\t * Returns `HasNonPublic` if `T` deeply may contain a private or protected field\n\t * and `OnlyPublics` otherwise.\n\t *\n\t * @remarks\n\t * Compare original (unprocessed) to filtered case that has `never` where\n\t * recursing or where allowed exception types are used.\n\t *\n\t * Note that this a test of the type and not the actual data. So, if an\n\t * interface is given as `T` where implemented by a class, any private or\n\t * protected fields within the class will not be detected.\n\t *\n\t * @system\n\t */\n\texport type IfNonPublicProperties<\n\t\tT,\n\t\tControls extends FilterControls,\n\t\tHasNonPublic = never,\n\t\tOnlyPublics = unknown,\n\t> = ReplaceAllowancesAndRecursionWithNever<T, Controls> extends T\n\t\t? OnlyPublics\n\t\t: HasNonPublic;\n\n\t/**\n\t * Union of all types in a tuple.\n\t *\n\t * @system\n\t */\n\texport type TupleToUnion<T extends unknown[]> = T[number];\n\n\t// #region JsonSerializable implementation\n\n\t/**\n\t * Outer implementation of {@link JsonSerializable} handling meta cases\n\t * like classes (with non-public properties).\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls> & {\n\t\t\t/**\n\t\t\t * See {@link JsonSerializableOptions} for meaning and expected use.\n\t\t\t */\n\t\t\tIgnoreInaccessibleMembers?: \"ignore-inaccessible-members\";\n\t\t},\n\t\tTAncestorTypes extends unknown[] = [],\n\t\tTNextAncestor = T,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute type could be extracted to helper type, but is kept explicit here\n\t\t// to make JsonTypeWith and OpaqueJsonSerializable show explicitly in results for\n\t\t// users, rather than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute:\n\t\t\t| JsonTypeWith<\n\t\t\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t\t\t: never)\n\t\t\t\t\t| (Options extends { AllowExtensionOf: unknown }\n\t\t\t\t\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t: never)\n\t\t\t >\n\t\t\t| OpaqueJsonSerializable<\n\t\t\t\t\tunknown,\n\t\t\t\t\tOptions extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [],\n\t\t\t\t\tOptions extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never\n\t\t\t >;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy FilterControlsWithSubstitution, but Typescript wants a check */\n\t\t\tControls extends FilterControlsWithSubstitution\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: Options extends { IgnoreInaccessibleMembers: \"ignore-inaccessible-members\" }\n\t\t\t\t\t? JsonSerializableFilter<T, Controls, TAncestorTypes, TNextAncestor>\n\t\t\t\t\t: /* test for non-public properties (class instance type) */\n\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in primitives that may be branded to ignore intersection classes\n\t\t\t\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t? /* hidden props => test if it is array properties that are the problem */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonSerializableImpl<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: /* test for potentially branded primitive (intersection with a supported primitive) */\n\t\t\t\t\t\t\t\tT extends boolean | number | string\n\t\t\t\t\t\t\t\t? /* assume intersection is branding and allow as-is => */ T\n\t\t\t\t\t\t\t\t: /* not array => error */ SerializationErrorPerNonPublicProperties\n\t\t\t\t\t\t: /* no hidden properties => apply filtering => */ JsonSerializableFilter<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\tTNextAncestor\n\t\t\t\t\t\t\t>\n\t\t\t: never /* FilterControlsWithSubstitution assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonSerializable}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} and {@link OpaqueJsonDeserialized} instances\n\t * are limited to `Controls` given context supports.\n\t * `T` from the original Opaque type is preserved. In the case that this now\n\t * produces an improper type such as a `bigint` being let through that is no\n\t * longer supported, then the variance of `Controls` is expected to raise\n\t * the incompatibility error.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableOpaqueAllowances<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControlsWithSubstitution,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\t/* infer underlying data type */ T extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? T extends OpaqueJsonSerializable<TData, any, unknown> &\n\t\t\t\tOpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]> &\n\t\t\t\t\tOpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t: T extends OpaqueJsonSerializable<TData, any, unknown>\n\t\t\t\t? OpaqueJsonSerializable<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t\t\t: T extends OpaqueJsonDeserialized<TData, any, unknown>\n\t\t\t\t\t? OpaqueJsonDeserialized<\n\t\t\t\t\t\t\tTData,\n\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t>\n\t\t\t\t\t: \"internal error: failed to determine OpaqueJson* type\"\n\t\t: never;\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Helper for {@link JsonSerializableFilter} to determine if a property may\n\t * be `undefined` and selects from options for result.\n\t * Since `unknown` is a superset of `undefined`, it is given a special case.\n\t * Additionally since index signatures are inherently optional, `unknown` typed\n\t * values are treated as not undefined (`Result[\"Otherwise\"]`).\n\t *\n\t * @system\n\t */\n\texport type IfPossiblyUndefinedProperty<\n\t\tTKey extends keyof AnyRecord,\n\t\tTValue,\n\t\tResult extends {\n\t\t\tIfPossiblyUndefined: unknown;\n\t\t\tIfUnknownNonIndexed: unknown;\n\t\t\tOtherwise: unknown;\n\t\t},\n\t> = undefined extends TValue\n\t\t? unknown extends TValue\n\t\t\t? IfIndexOrBrandedKey<TKey, Result[\"Otherwise\"], Result[\"IfUnknownNonIndexed\"]>\n\t\t\t: Result[\"IfPossiblyUndefined\"]\n\t\t: Result[\"Otherwise\"];\n\n\t/**\n\t * Core implementation of {@link JsonSerializable}.\n\t *\n\t * @privateRemarks\n\t * Filtering through a single layer of recursion is all that is required\n\t * when using in prescribed filter scenario.\n\t *\n\t * @system\n\t */\n\texport type JsonSerializableFilter<\n\t\tT,\n\t\tControls extends FilterControlsWithSubstitution,\n\t\tTAncestorTypes extends unknown[],\n\t\tTNextAncestor = T,\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for recursion */ IfExactTypeInTuple<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t> extends true\n\t\t\t\t? /* exact recursion; stop here => */ T\n\t\t\t\t: /* test for JSON Encodable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t\t| null\n\t\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t\t| number\n\t\t\t\t\t\t\t| string\n\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t\t: /* test for exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\"no match\"\n\t\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t\t: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\t\t\t\t\t\t/* test for not a function */ Extract<T, Function> extends never\n\t\t\t\t\t\t\t? /* not a function => test for object */ T extends object\n\t\t\t\t\t\t\t\t? /* object => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForSerializableArrayItem<\n\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\tTAncestorTypes,\n\t\t\t\t\t\t\t\t\t\t\t\tJsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t\t? /* `object` => */ NonNullJsonObjectWith<\n\t\t\t\t\t\t\t\t\t\t\t\tTupleToUnion<Controls[\"AllowExactly\"]> | Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t\t: /* test for OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonSerializableOpaqueAllowances<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* required properties are recursed and may not have undefined values. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as RequiredNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]-?: IfPossiblyUndefinedProperty<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfPossiblyUndefined: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `undefined` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tIfUnknownNonIndexed: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\"error required property may not allow `unknown` value\"]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tOtherwise: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* optional properties are recursed and, when exactOptionalPropertyTypes is\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t false, are allowed to preserve undefined value type. */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as OptionalNonSymbolKeysOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonSerializableFilter<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[TNextAncestor, ...TAncestorTypes]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* symbol properties are rejected */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T & symbol]: never;\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t: /* not an object => */ never\n\t\t\t\t\t\t\t: /* function => */ never;\n\n\t// #endregion\n\n\t/**\n\t * Sentinel type for use when marking points of recursion (in a recursive type).\n\t * Type is expected to be unique, though no lengths are taken to ensure that.\n\t *\n\t * @system\n\t */\n\texport interface RecursionMarker {\n\t\t[RecursionMarkerSymbol]: typeof RecursionMarkerSymbol;\n\t}\n\n\t// #region JsonDeserialized implementation\n\n\t/**\n\t * Outer implementation of {@link JsonDeserialized} handling meta cases\n\t * like recursive types.\n\t *\n\t * @remarks\n\t * If no modification is needed (`T` is exactly deserializable), `T` will\n\t * be the result.\n\t *\n\t * Upon recursion with `T` that requires modification, `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing.\n\t * Caller will need to unwrap the type to continue processing.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedImpl<\n\t\tT,\n\t\tOptions extends Partial<FilterControls>,\n\t\tTypeUnderRecursion extends boolean = false,\n\t> = /* Build Controls from Options filling in defaults for any missing properties */\n\t{\n\t\tAllowExactly: Options extends { AllowExactly: unknown[] } ? Options[\"AllowExactly\"] : [];\n\t\tAllowExtensionOf: Options extends { AllowExtensionOf: unknown }\n\t\t\t? Options[\"AllowExtensionOf\"]\n\t\t\t: never;\n\t\t// The Substitute types could be extracted to helper type, but are kept explicit here\n\t\t// to make JsonTypeWith/NonNullJsonObjectWith show explicitly in results for users, rather\n\t\t// than either the helper type name or a partially unrolled version.\n\t\tDegenerateSubstitute: JsonTypeWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tDegenerateNonNullObjectSubstitute: NonNullJsonObjectWith<\n\t\t\t| (Options extends { AllowExactly: unknown[] }\n\t\t\t\t\t? TupleToUnion<Options[\"AllowExactly\"]>\n\t\t\t\t\t: never)\n\t\t\t| (Options extends { AllowExtensionOf: unknown } ? Options[\"AllowExtensionOf\"] : never)\n\t\t>;\n\t\tRecursionMarkerAllowed: never;\n\t} extends infer Controls\n\t\t? /* Controls should always satisfy DeserializedFilterControls, but Typescript wants a check */\n\t\t\tControls extends DeserializedFilterControls\n\t\t\t? /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t\t: /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tRecursionMarker,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t// Also preserve OpaqueJson* types\n\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t> extends infer TNoRecursionAndOnlyPublics\n\t\t\t\t\t? /* test for no change from filtered type */ IsSameType<\n\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\tJsonDeserializedFilter<\n\t\t\t\t\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf: Controls[\"AllowExtensionOf\"];\n\t\t\t\t\t\t\t\t\tDegenerateSubstitute: Controls[\"DegenerateSubstitute\"];\n\t\t\t\t\t\t\t\t\tDegenerateNonNullObjectSubstitute: Controls[\"DegenerateNonNullObjectSubstitute\"];\n\t\t\t\t\t\t\t\t\tRecursionMarkerAllowed: RecursionMarker;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t\t? /* same (no filtering needed) => test for non-public\n\t\t\t\t\t\t properties (class instance type) */\n\t\t\t\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t\t\t\t// primitives as JsonDeserializedFilter will allow them as\n\t\t\t\t\t\t\t\t// extensions of the primitives. Should there be a need to\n\t\t\t\t\t\t\t\t// explicitly allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tAllowExactly: Controls[\"AllowExactly\"];\n\t\t\t\t\t\t\t\t\tAllowExtensionOf:\n\t\t\t\t\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t\t// Add in OpaqueJson* types\n\t\t\t\t\t\t\t\t\t\t| AnyOpaqueJsonType;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\t\t\t\"only publics\"\n\t\t\t\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t\t\t\t? /* hidden props => apply filtering to avoid retaining\n\t\t\t\t\t\t\t exact class except for any classes in allowances =>\n\t\t\t\t\t\t\t\t test for known recursion */\n\t\t\t\t\t\t\t\tTypeUnderRecursion extends false\n\t\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t: /* no hidden properties => deserialized T is just T */\n\t\t\t\t\t\t\t\tT\n\t\t\t\t\t\t: /* filtering is needed => test for known recursion */ TypeUnderRecursion extends false\n\t\t\t\t\t\t\t? /* no known recursion => */ JsonDeserializedFilter<T, Controls>\n\t\t\t\t\t\t\t: /* known recursion => use OpaqueJsonDeserialized for later processing */\n\t\t\t\t\t\t\t\tOpaqueJsonDeserialized<\n\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\tControls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"]\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t: /* unreachable else for infer */ never\n\t\t\t: never /* DeserializedFilterControls assert else; should never be reached */\n\t\t: never /* unreachable else for infer */;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.JsonDeserializedFilter} up until\n\t * `T` is found to be a match of an ancestor type. At that point `T` is wrapped in\n\t * {@link OpaqueJsonDeserialized} to avoid further immediate processing, if\n\t * modification is needed. Caller will need to unwrap the type to continue processing.\n\t * If no modification is needed, then `T` will be the result.\n\t *\n\t * @privateRemarks Exact recursion pattern employed should allow shortcut\n\t * test to return `OpaqueJsonDeserialized<T>` from here when the exact\n\t * recursion match is the first ancestor type in tuple as it must have been\n\t * processed and found to need modification.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedRecursion<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\tTAncestorTypes extends object[],\n\t> = IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t? /* recursion found => reprocess that recursive type directly to avoid\n\t\t any collateral damage from ancestor type that required modification.\n\t\t\t Further recursion will not happen during processing. Either:\n\t\t\t - the type requires modification and the `TypeUnderRecursion=true`\n\t\t\t arg will result in `OpaqueJsonDeserialized<T>` wrapper OR\n\t\t\t - no change is needed from this point and `T` will result. */\n\t\t\tJsonDeserializedImpl<T, Controls, true>\n\t\t: T extends object\n\t\t\t? IfExactTypeInTuple<T, TAncestorTypes, true, \"no match\"> extends true\n\t\t\t\t? JsonDeserializedImpl<T, Controls, true>\n\t\t\t\t: /* no recursion yet detected => */ JsonDeserializedFilter<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tControls,\n\t\t\t\t\t\t[...TAncestorTypes, T]\n\t\t\t\t\t>\n\t\t\t: /* not an object (no recursion) => */ JsonDeserializedFilter<\n\t\t\t\t\tT,\n\t\t\t\t\tControls,\n\t\t\t\t\tTAncestorTypes\n\t\t\t\t>;\n\n\t/**\n\t * Handle OpaqueJson* types for {@link JsonDeserialized}.\n\t *\n\t * @remarks\n\t * {@link OpaqueJsonSerializable} instances are converted to {@link OpaqueJsonDeserialized}.\n\t * The `AllowExactly` and `AllowExtensionOf` properties are set to match the given `Controls`.\n\t * The data type is kept exactly as-is to avoid processing in generic contexts that can't\n\t * produce a meaningful result. The data type should always be filtered through\n\t * {@link JsonDeserialized} when {@link OpaqueJsonDeserialized} is cracked open. So, really\n\t * the filtering is just deferred.\n\t *\n\t * @privateRemarks\n\t * Additional intersections beyond {@link OpaqueJsonSerializable},\n\t * {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are\n\t * not correctly filtered as need is not expected.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedOpaqueConversion<\n\t\tT extends AnyOpaqueJsonType,\n\t\tControls extends FilterControls,\n\t> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */\n\tT extends\n\t\t| OpaqueJsonSerializable<infer TData, any, unknown>\n\t\t| OpaqueJsonDeserialized<infer TData, any, unknown>\n\t\t? OpaqueJsonDeserialized<TData, Controls[\"AllowExactly\"], Controls[\"AllowExtensionOf\"]>\n\t\t: \"internal error: failed to determine OpaqueJson* type\";\n\t/* eslint-enable @typescript-eslint/no-explicit-any */\n\n\t/**\n\t * Core implementation of {@link JsonDeserialized}.\n\t *\n\t * @system\n\t */\n\texport type JsonDeserializedFilter<\n\t\tT,\n\t\tControls extends DeserializedFilterControls,\n\t\t// Always start with object portion of self as ancestor. Filtering will\n\t\t// not apply past recursion (nested occurrence of this).\n\t\tTAncestorTypes extends object[] = [Extract<T, object>],\n\t> = /* test for 'any' */ boolean extends (T extends never ? true : false)\n\t\t? /* 'any' => */ Controls[\"DegenerateSubstitute\"]\n\t\t: /* test for 'unknown' */ unknown extends T\n\t\t\t? /* 'unknown' => */ Controls[\"DegenerateSubstitute\"]\n\t\t\t: /* test for deserializable primitive types or given alternate base */ T extends\n\t\t\t\t\t\t| null\n\t\t\t\t\t\t| boolean\n\t\t\t\t\t\t| number\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| Controls[\"AllowExtensionOf\"]\n\t\t\t\t? /* primitive types or alternate => */ T\n\t\t\t\t: /* test for given exact alternate */ IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[...Controls[\"AllowExactly\"], Controls[\"RecursionMarkerAllowed\"]],\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\"not found\"\n\t\t\t\t\t\t> extends true\n\t\t\t\t\t? /* exact alternate type => */ T\n\t\t\t\t\t: /* test for object */ T extends object\n\t\t\t\t\t\t? /* object => */ ExtractFunctionFromIntersection<T> extends {\n\t\t\t\t\t\t\t\tclassification: \"exactly Function\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t? /* exactly function => */ never\n\t\t\t\t\t\t\t: /* not exactly a function (Function portion, if any, is omitted) */\n\t\t\t\t\t\t\t\t/* => test for array */ T extends readonly (infer _)[]\n\t\t\t\t\t\t\t\t? /* array => */ {\n\t\t\t\t\t\t\t\t\t\t/* array items may not not allow undefined */\n\t\t\t\t\t\t\t\t\t\t/* use homomorphic mapped type to preserve tuple type */\n\t\t\t\t\t\t\t\t\t\t[K in keyof T]: JsonForDeserializedArrayItem<\n\t\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\t\tControls,\n\t\t\t\t\t\t\t\t\t\t\tJsonDeserializedRecursion<T[K], Controls, TAncestorTypes>\n\t\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: /* not an array => test for exactly `object` */ IsExactlyObject<T> extends true\n\t\t\t\t\t\t\t\t\t? /* `object` => */ Controls[\"DegenerateNonNullObjectSubstitute\"]\n\t\t\t\t\t\t\t\t\t: /* test for enum like types */ IfEnumLike<T> extends never\n\t\t\t\t\t\t\t\t\t\t? /* enum or similar simple type (return as-is) => */ T\n\t\t\t\t\t\t\t\t\t\t: /* test for matching OpaqueJson* types */ T extends AnyOpaqueJsonType\n\t\t\t\t\t\t\t\t\t\t\t? /* OpaqueJson* type => */ JsonDeserializedOpaqueConversion<T, Controls>\n\t\t\t\t\t\t\t\t\t\t\t: /* property bag => */ FlattenIntersection<\n\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with symbol keys or wholly unsupported values are removed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* properties with defined values are recursed */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolWithDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t} & {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t/* literal properties that may have undefined values are optional */\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t[K in keyof T as NonSymbolLiteralWithPossiblyDeserializablePropertyOf<\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t...Controls[\"AllowExactly\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"RecursionMarkerAllowed\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tControls[\"AllowExtensionOf\"],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tK\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>]?: JsonDeserializedRecursion<T[K], Controls, TAncestorTypes>;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t: /* not an object => */ never;\n\n\t// #endregion\n\n\t// #region *Readonly implementations\n\n\t/**\n\t * Recursion limit is the count of `+` that prefix it when string.\n\t *\n\t * @system\n\t */\n\texport type RecursionLimit = `+${string}` | 0;\n\n\t/**\n\t * If `T` is a `Map<K,V>` or `ReadonlyMap<K,V>`, returns `ReadonlyMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlyMap<infer K, infer V>\n\t\t? Map<K, V> extends DeepenedGenerics\n\t\t\t? ReadonlyMap<\n\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t>\n\t\t\t: ReadonlyMap<K, V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Set<TSet>` or `ReadonlySet<TSet>`, returns `ReadonlySet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends ReadonlySet<infer V>\n\t\t? Set<V> extends DeepenedGenerics\n\t\t\t? ReadonlySet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: ReadonlySet<V>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `IFluidHandle<THandle>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `THandle` generic.\n\t * `Else` is returned if not an `IFluidHandle`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInFluidHandleIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Readonly<IFluidHandle<infer V>>\n\t\t? IFluidHandle<V> extends DeepenedGenerics\n\t\t\t? Readonly<IFluidHandle<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>>\n\t\t\t: Readonly<T>\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `Promise<TPromise>` and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `TPromise` generic.\n\t * `Else` is returned if not a `Promise`.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInPromiseIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Promise<infer V>\n\t\t? Promise<V> extends DeepenedGenerics\n\t\t\t? Promise<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>\n\t\t\t: T\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakMap<K,V>`, returns immutable `WeakMap` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `K` and `V` generics. `Else` is returned if not a generic map.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakMap<infer K, infer V>, \"delete\" | \"set\">\n\t\t? WeakMap<K, V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakMap<\n\t\t\t\t\t\tReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,\n\t\t\t\t\t\tReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>\n\t\t\t\t\t>,\n\t\t\t\t\t\"delete\" | \"set\"\n\t\t\t\t>\n\t\t\t: Omit<WeakMap<K, V>, \"delete\" | \"set\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a `WeakSet<TSet>`, returns immutable `WeakSet` and,\n\t * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to\n\t * `TSet` generic. `Else` is returned if not a generic weak set.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInWeakSetIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = T extends Omit<WeakSet<infer V>, \"add\" | \"delete\">\n\t\t? WeakSet<V> extends DeepenedGenerics\n\t\t\t? Omit<\n\t\t\t\t\tWeakSet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>,\n\t\t\t\t\t\"add\" | \"delete\"\n\t\t\t\t>\n\t\t\t: Omit<WeakSet<V>, \"add\" | \"delete\">\n\t\t: Else;\n\n\t/**\n\t * If `T` is a {@link ReadonlySupportedGenerics}, `T` is returned as\n\t * its immutable version, and if `T` extends `DeepenedGenerics`,\n\t * {@link DeepReadonly} is applied to `T`s generics.\n\t *\n\t * @system\n\t */\n\texport type DeepenReadonlyInGenerics<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t\tElse,\n\t> = DeepenReadonlyInMapIfEnabled<\n\t\tT,\n\t\tDeepenedGenerics,\n\t\tNoDepthOrRecurseLimit,\n\t\tDeepenReadonlyInSetIfEnabled<\n\t\t\tT,\n\t\t\tDeepenedGenerics,\n\t\t\tNoDepthOrRecurseLimit,\n\t\t\tDeepenReadonlyInWeakMapIfEnabled<\n\t\t\t\tT,\n\t\t\t\tDeepenedGenerics,\n\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\tDeepenReadonlyInWeakSetIfEnabled<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\tDeepenReadonlyInPromiseIfEnabled<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\tDeepenReadonlyInFluidHandleIfEnabled<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\tNoDepthOrRecurseLimit,\n\t\t\t\t\t\t\tElse\n\t\t\t\t\t\t>\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t>\n\t>;\n\n\t/**\n\t * Returns an `ErasedType` or \"branded\" primitive type as-is, or `Else` if not.\n\t * @typeParam T - Type to test.\n\t * @typeParam Else - Type to return if not `ErasedType` or \"branded\" primitive.\n\t *\n\t * @system\n\t */\n\texport type PreserveErasedTypeOrBrandedPrimitive<\n\t\tT extends object,\n\t\tElse,\n\t> = /* Test for erased type */ T extends ErasedType<infer _>\n\t\t? /* erased type => keep as-is */ T\n\t\t: /* Test for branded primitive */ T extends infer Brand &\n\t\t\t\t\t(boolean | number | string | symbol | bigint)\n\t\t\t? // Should just return T here, but TypeScript appears to produce `never` when doing so.\n\t\t\t\t// Workaround by inferring the Primitive type and returning intersection with B.\n\t\t\t\tT extends Brand & infer Primitive\n\t\t\t\t? /* [potentially] branded type => \"as-is\" */ Primitive & Brand\n\t\t\t\t: /* Should never be reached */ T\n\t\t\t: Else;\n\n\t/**\n\t * De-multiplexing implementation of {@link DeepReadonly} and {@link ShallowReadonly}\n\t * selecting behavior based on `NoDepthOrRecurseLimit`.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant. Its importance is that other utilities common to\n\t * readonly transformation may use `NoDepthOrRecurseLimit` to return the the\n\t * same processing algorithm.\n\t *\n\t * @system\n\t */\n\texport type ReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends \"Shallow\" | DeepReadonlyRecursionLimit,\n\t> = /* test for no depth */ NoDepthOrRecurseLimit extends \"Shallow\"\n\t\t? /* no depth => */ ShallowReadonlyImpl<T, DeepenedGenerics>\n\t\t: /* test for no limit */ NoDepthOrRecurseLimit extends \"NoLimit\"\n\t\t\t? /* no limit => */ DeepReadonlyRecursingInfinitely<T, DeepenedGenerics>\n\t\t\t: /* limited */ DeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>;\n\n\t// #region ShallowReadonly implementation\n\n\t/**\n\t * Outer implementation of {@link ShallowReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility can be reentrant when generics are deepened.\n\t *\n\t * @system\n\t */\n\texport type ShallowReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\"Shallow\",\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<T, /* basic type => */ Readonly<T>>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\n\t/**\n\t * Outer implementation of {@link DeepReadonly}.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `RecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyImpl<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends DeepReadonlyRecursionLimit,\n\t> = ReadonlyImpl<T, DeepenedGenerics, RecurseLimit>;\n\n\t// #region DeepReadonly infinite recursion implementation\n\n\t/**\n\t * Simple implementation of {@link DeepReadonly} that may handle limited recursive types.\n\t * In unhandled cases, TypeScript will produce:\n\t * ts(2589): Type instantiation is excessively deep and possibly infinite.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursingInfinitely<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t> = T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\t// test for array of known recursive type: JsonTypeWith\n\t\t\t\tT extends readonly ReadonlyJsonTypeWith<infer Alternates>[]\n\t\t\t\t\t? // Make sure this is exactly that case (many arrays will extend JsonTypeWith)\n\t\t\t\t\t\t// Note that `true extends IfExactTypeInTuple` is used over\n\t\t\t\t\t\t// if-else form as the else branch would be evaluated as input to\n\t\t\t\t\t\t// `IfExactTypeInTuple` and that could lead to infinite recursion.\n\t\t\t\t\t\ttrue extends IfExactTypeInTuple<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t[JsonTypeWith<Alternates>[], readonly ReadonlyJsonTypeWith<Alternates>[]]\n\t\t\t\t\t\t>\n\t\t\t\t\t\t? readonly ReadonlyJsonTypeWith<\n\t\t\t\t\t\t\t\tDeepReadonlyRecursingInfinitely<Alternates, DeepenedGenerics>\n\t\t\t\t\t\t\t>[]\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t: /* not JSON array => */ DeepenReadonlyInGenerics<\n\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\"NoLimit\",\n\t\t\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\t\t\tT,\n\t\t\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursingInfinitely<\n\t\t\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\t\t\tDeepenedGenerics\n\t\t\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #region DeepReadonly limited recursion implementation\n\n\t/**\n\t * Core implementation of {@link DeepReadonly} handling meta cases\n\t * like recursive types a limited number of times.\n\t *\n\t * @privateRemarks\n\t * This utility is reentrant and will process a type `T` up to `NoDepthOrRecurseLimit`.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyLimitingRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tNoDepthOrRecurseLimit extends RecursionLimit,\n\t> = /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<\n\t\tT,\n\t\tRecursionMarker,\n\t\t{ AllowExactly: []; AllowExtensionOf: never }\n\t> extends infer TNoRecursionAndOnlyPublics\n\t\t? /* test for no change from altered type (excluding non-publics) */ IsSameType<\n\t\t\t\tTNoRecursionAndOnlyPublics,\n\t\t\t\tDeepReadonlyWorker<TNoRecursionAndOnlyPublics, DeepenedGenerics, 0>\n\t\t\t> extends true\n\t\t\t? /* same (no filtering needed) => test for non-public properties (class instance type) */\n\t\t\t\tIfNonPublicProperties<\n\t\t\t\t\tT,\n\t\t\t\t\t// Note: no extra allowance is made here for possible branded\n\t\t\t\t\t// primitives as DeepReadonlyWorker will allow them as\n\t\t\t\t\t// extensions of the primitives. Should there need a need to\n\t\t\t\t\t// explicit allow them here, see JsonSerializableImpl's use.\n\t\t\t\t\t{ AllowExactly: []; AllowExtensionOf: never },\n\t\t\t\t\t\"found non-publics\",\n\t\t\t\t\t\"only publics\"\n\t\t\t\t> extends \"found non-publics\"\n\t\t\t\t? /* hidden props => apply filtering => */\n\t\t\t\t\tDeepReadonlyWorker<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t\t>\n\t\t\t\t: /* no hidden properties => readonly T is just T */\n\t\t\t\t\tT\n\t\t\t: /* filtering is needed => */ DeepReadonlyWorker<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tExtract<NoDepthOrRecurseLimit, RecursionLimit>\n\t\t\t\t>\n\t\t: /* unreachable else for infer */ never;\n\n\t/**\n\t * Recurses `T` applying {@link InternalUtilityTypes.DeepReadonlyWorker} up to `RecurseLimit` times.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyRecursion<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = T extends TAncestorTypes\n\t\t? RecurseLimit extends `+${infer RecursionRemainder}`\n\t\t\t? /* Now that specific recursion is found, process that recursive type\n\t\t\t directly to avoid any collateral damage from ancestor type that\n\t\t\t required modification. */\n\t\t\t\tDeepReadonlyLimitingRecursion<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecursionRemainder extends RecursionLimit ? RecursionRemainder : 0\n\t\t\t\t>\n\t\t\t: T\n\t\t: DeepReadonlyWorker<T, DeepenedGenerics, RecurseLimit, TAncestorTypes | T>;\n\n\t/**\n\t * Core implementation of {@link InternalUtilityTypes.DeepReadonlyLimitingRecursion}.\n\t *\n\t * @system\n\t */\n\texport type DeepReadonlyWorker<\n\t\tT,\n\t\tDeepenedGenerics extends ReadonlySupportedGenerics,\n\t\tRecurseLimit extends RecursionLimit,\n\t\tTAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,\n\t> = /* test for object */ T extends object\n\t\t? /* object => */ FilterPreservingFunction<\n\t\t\t\tT,\n\t\t\t\tDeepenReadonlyInGenerics<\n\t\t\t\t\tT,\n\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\tRecurseLimit,\n\t\t\t\t\tPreserveErasedTypeOrBrandedPrimitive<\n\t\t\t\t\t\tT,\n\t\t\t\t\t\t/* basic type => */ {\n\t\t\t\t\t\t\treadonly [K in keyof T]: DeepReadonlyRecursion<\n\t\t\t\t\t\t\t\tT[K],\n\t\t\t\t\t\t\t\tDeepenedGenerics,\n\t\t\t\t\t\t\t\tRecurseLimit,\n\t\t\t\t\t\t\t\tTAncestorTypes\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t>\n\t\t\t>\n\t\t: /* not an object => */ T;\n\n\t// #endregion\n\t// #endregion\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/core-interfaces",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.74.0-365691",
|
|
4
4
|
"description": "Fluid object interfaces",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"@fluid-tools/build-cli": "^0.60.0",
|
|
87
87
|
"@fluidframework/build-common": "^2.0.3",
|
|
88
88
|
"@fluidframework/build-tools": "^0.60.0",
|
|
89
|
-
"@fluidframework/core-interfaces-previous": "npm:@fluidframework/core-interfaces@2.
|
|
90
|
-
"@fluidframework/eslint-config-fluid": "
|
|
89
|
+
"@fluidframework/core-interfaces-previous": "npm:@fluidframework/core-interfaces@2.73.0",
|
|
90
|
+
"@fluidframework/eslint-config-fluid": "2.74.0-365691",
|
|
91
91
|
"@microsoft/api-extractor": "7.52.11",
|
|
92
92
|
"@types/mocha": "^10.0.10",
|
|
93
93
|
"@types/node": "^18.19.0",
|
|
@@ -212,7 +212,7 @@ export namespace InternalUtilityTypes {
|
|
|
212
212
|
| symbol
|
|
213
213
|
| undefined
|
|
214
214
|
? /* not serializable => */ Result["WhenNeverDeserializable"]
|
|
215
|
-
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
215
|
+
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
216
216
|
T extends Function
|
|
217
217
|
? ExtractFunctionFromIntersection<T> extends {
|
|
218
218
|
classification: "exactly Function";
|
|
@@ -307,7 +307,7 @@ export namespace InternalUtilityTypes {
|
|
|
307
307
|
/* extract types that might lead to missing property */ Extract<
|
|
308
308
|
PossibleTypeLessAllowed,
|
|
309
309
|
/* types that might lead to missing property, except `bigint` */
|
|
310
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
311
311
|
undefined | symbol | Function
|
|
312
312
|
> extends never
|
|
313
313
|
? /* all types are supported plus possibly `bigint` => */
|
|
@@ -371,7 +371,7 @@ export namespace InternalUtilityTypes {
|
|
|
371
371
|
? Extract<
|
|
372
372
|
IfSameType<PossibleTypeLessAllowed, unknown, undefined, PossibleTypeLessAllowed>,
|
|
373
373
|
/* types that might lead to missing property */
|
|
374
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
374
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
375
375
|
undefined | symbol | Function
|
|
376
376
|
> extends never
|
|
377
377
|
? /* exclusively supported types or exactly `never` */ never
|
|
@@ -463,7 +463,7 @@ export namespace InternalUtilityTypes {
|
|
|
463
463
|
/* exactly replaced => */ T,
|
|
464
464
|
/* test for known types that become null */ T extends undefined | symbol
|
|
465
465
|
? /* => */ null
|
|
466
|
-
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
466
|
+
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
467
467
|
T extends Function
|
|
468
468
|
? ExtractFunctionFromIntersection<T> extends {
|
|
469
469
|
classification: "exactly Function";
|
|
@@ -484,7 +484,7 @@ export namespace InternalUtilityTypes {
|
|
|
484
484
|
NotEnumLike = unknown,
|
|
485
485
|
> = T extends readonly (infer _)[]
|
|
486
486
|
? /* array => */ NotEnumLike
|
|
487
|
-
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
487
|
+
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
488
488
|
T extends Function
|
|
489
489
|
? /* function => */ NotEnumLike
|
|
490
490
|
: T extends {
|
|
@@ -1050,7 +1050,7 @@ export namespace InternalUtilityTypes {
|
|
|
1050
1050
|
"no match"
|
|
1051
1051
|
> extends true
|
|
1052
1052
|
? /* exact alternate type => */ T
|
|
1053
|
-
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
1053
|
+
: // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
1054
1054
|
/* test for not a function */ Extract<T, Function> extends never
|
|
1055
1055
|
? /* not a function => test for object */ T extends object
|
|
1056
1056
|
? /* object => test for array */ T extends readonly (infer _)[]
|