import type { NotExtendable } from './Extends.js';
import type { IsEmptyObject } from './IsEmptyObject.js';
/**
 * Can `A` assign to `B`
 *
 * Note that when union is involved, the assignability is measured distributively.
 * Meaning the result can be `Then | Else` (i.e. `boolean` by default),
 * instead of distinctive `Then` (`true`) or `Else` (`false`).
 *
 * This is the correct behavior.
 *
 * @example
 * ```ts
 * CanAssign<number | string, number> // boolean
 * ```
 *
 * We are checking can `A` assign to `B`.
 * Since `A` is `number | string`,
 * `A` can assign to `B` when `A` is number` (true), and
 * `A` cannot assign to `B` when `A` is string` (false).
 * So the result is `true | false = boolean`.
 *
 * If you want to make sure all branches are assignable,
 * use `StrictCanAssign<A, B>`.
 */
export type CanAssign<A, B, Then = true, Else = false> = IsEmptyObject<A> extends true ? Record<string, unknown> extends B ? Then : Else : boolean extends A ? boolean extends B ? Then : Else : A extends B ? Then : Else;
/**
 * Can `A` strictly assign to `B`.
 *
 * All branches in an union `A` are assignable to `B`.
 *
 * @example
 * ```ts
 * StrictCanAssign<number | string, number> // false
 * StrictCanAssign<number | string, number | string> // true
 * ```
 */
export type StrictCanAssign<A, B, Then = true, Else = false> = IsEmptyObject<A> extends true ? Record<string, unknown> extends B ? Then : Else : boolean extends A ? boolean extends B ? Then : Else : [A] extends [B] ? Then : Else;
/**
 * @deprecated use `CanAssign` instead
 */
export type IsAssign<A, B, Then = true, Else = false> = CanAssign<A, B, Then, Else>;
export declare function canAssign<T>(canAssign: false): <S>(subject: NotExtendable<S, T>) => true;
export declare function canAssign<T>(): <S extends T>(subject: S) => CanAssign<S, T>;
//# sourceMappingURL=CanAssign.d.ts.map