An overlapping technique (covering some but not all of the circumstances you'd use assert) is to take a parse-dont-validate approach, and essentially encode the fact that an assertion has been applied to a value in its type.
How ergonomic this is will vary by language, but the general idea would be to apply the assertion logic in some sort of constructor, then prevent any operations which would break the invariant going forward. The simplest way to protect this being by making the value immutable where possible.
Users of the value who care about the invariant being true can then specify in their types that they want a non-empty-collection or a foo-id or whatever it may be, rather than asking for the wider type, then asserting.
How ergonomic this is will vary by language, but the general idea would be to apply the assertion logic in some sort of constructor, then prevent any operations which would break the invariant going forward. The simplest way to protect this being by making the value immutable where possible.
Users of the value who care about the invariant being true can then specify in their types that they want a non-empty-collection or a foo-id or whatever it may be, rather than asking for the wider type, then asserting.