What're Differences Between `typed/racket/unsafe` and `typed/racket/optional`?

I'm writing a module that adds types to identifiers imported from untyped code, and I want to avoid contract generation. I see two approaches:

Using typed/racket/unsafe:

(require typed/racket/unsafe)

Using typed/racket/optional with renamed imports:

(require (rename-in typed/racket/base/optional
                    [require/typed unsafe-require/typed]
                    [provide unsafe-provide]
                    [require/typed/provide unsafe-require/typed/provide]
                    [cast unsafe-cast]))

My goal: Type bindings from untyped modules, trusting that the values already match their types.

Both approaches seem to bypass contract generation. But I'm unsure about their exact differences. Could someone clarify:

  1. Are these approaches interchangeable, or do they have meaningful technical differences?

  2. When should each be preferred?

I'd appreciate any insights about these mechanisms or pointers to relevant documentation. Thanks!

On May 16, 2025, at 12:59 AM, Noah Ma via Racket Discourse notifications@racket.discoursemail.com says he wants "Type bindings from untyped modules, trusting that the values already match their types” and asks whether someone “could .. clarify”. Given your goal, you want #lang typed/racket/optional as your module level language. (Ben G. created the ‘shallow’ and ‘optional’ variants for his research on making the overhead of T/U interactions tolerable.)