/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { UsageError } from "@fluidframework/telemetry-utils/internal";
/**
 * Implementation detail for {@link Brand}.
 *
 * See `MakeNominal` for some more details.
 *
 * Do not use this class with `instanceof`: this will always be false at runtime,
 * but the compiler may think it's true in some cases.
 *
 * @remarks
 * This is covariant over ValueType.
 * This is suitable for when ValueType is immutable (like string or number),
 * which is the common use-case for branding.
 *
 * @privateRemarks
 * This is split out into its own type as that's the only way to:
 *
 * - make the member protected (so you can't accidentally try and access it).
 * - get nominal typing (so types produced without using this class can never be assignable to it).
 *
 * @sealed
 */
export class BrandedType {
    /**
     * This class should never exist at runtime, so make it un-constructable.
     */
    constructor() { }
    /**
     * Since this class is a compile time only type brand, `instanceof` will never work with it.
     * This `Symbol.hasInstance` implementation ensures that `instanceof` will error if used,
     * and in TypeScript 5.3 and newer will produce a compile time error if used.
     */
    static [Symbol.hasInstance](value) {
        throw new UsageError("BrandedType is a compile time type brand not a real class that can be used with `instanceof` at runtime.");
    }
}
/**
 * Adds a type {@link Brand} to a value.
 *
 * Only do this when specifically allowed by the requirements of the type being converted to.
 * @remarks
 * This infers the branded type from context so it can very easily be used to a semantically invalid conversion.
 * Treat this like "as" casts: they are an indicator that the user/reader must ensure the conversion is valid.
 *
 * If branding a constant, and wanting to preserve the exact typing of the constant, use {@link brandConst} instead.
 * @privateRemarks
 * Leaving `T` unconstrained here allows for better type inference when branding unions.
 * For example when assigning `brand(number)` a number to an optional branded number field,
 * constraining T to `BrandedType<unknown, string>` causes the inference to fail and requires explicitly providing the type parameter.
 * For example leaving T unconstrained instead allows the union of `BrandedType | undefined` to distribute over the conditional allowing the branding only the the union members which should be branded.
 * This does not permit branding an optional value into an optional field since non branded union members are still excluded from input to this function:
 * this is an intended restriction as it causes compile errors for misuse of this function (like using brand when the relevant type is not a branded type).
 */
export function brand(value) {
    return value;
}
/**
 * Adds a type {@link Brand} to a value, while preserving the exact type of the value being branded.
 * @remarks
 * This takes in the type to brand to as a required type parameter, unlike {@link brand} which infers it from context.
 * This also preserves the exact type of the value being branded.
 * TypeScript has no way to take an explicit type parameter and infer another in a single generic context.
 * To work around this, two generic contexts are used, first a function to infer the parameter type,
 * and a second function (returned) to take the explicit type parameter.
 *
 * This is intended for use when branding constants.
 * @example
 * ```typescript
 * const requiredIdentifier = brandConst("Value")<FieldKindIdentifier>();
 * ```
 * @privateRemarks
 * The dummy parameter is used to produce a compile error in the event where the value being branded is incompatible with the branded type.
 */
export function brandConst(value) {
    return () => value;
}
/**
 * Removes a type brand from a branded value.
 * @remarks
 * This is useful when trying to do an exhaustive switch over a union of branded types,
 * which for some reason fails if the brand is not removed from the "case" entries.
 */
export function unbrand(value) {
    return value;
}
/**
 * Make an enum like object using {@link Brand} to brand the values.
 * @remarks
 * This has stricter typing than TypeScript built in enums since it does not allow implicit assignment of `number` to enums with a numeric value.
 * It also blocks implicit conversions of individual constants to the enum type:
 * such cases must use {@link brand} or get the branded value from the enum instead.
 *
 * One limitation is that narrowing does not work in switch statements:
 * the values in each case can use {@link unbrand} to work around this.
 *
 * This object does not provide {@link https://www.typescriptlang.org/docs/handbook/enums.html#reverse-mappings | reverse mappings}.
 *
 * @example
 * ```typescript
 * const TestA = strictEnum("TestA", {
 * 	a: 1,
 * 	b: 2,
 * });
 * type TestA = Values<typeof TestA>;
 *
 * function switchUnbrand(x: TestA) {
 * 	switch (x) {
 * 		case unbrand(TestA.a):
 * 			return "a";
 * 		case unbrand(TestA.b):
 * 			return "b";
 * 		default:
 * 			unreachableCase(x);
 * 	}
 * }
 * ```
 */
export function strictEnum(name, entries) {
    return entries;
}
//# sourceMappingURL=brand.js.map