uber-go / fx

A dependency injection based application framework for Go.
https://uber-go.github.io/fx/
MIT License
5.72k stars 289 forks source link

fx.Self: a parameter to fx.As for providing a type as itself #1201

Closed JacobOaks closed 4 months ago

JacobOaks commented 4 months ago

We frequently see requests for folks who want to use fx.As to provide a type as another type, while also providing it as itself. To name a few:

This is currently not possible via strictly using fx.As + a single constructor, since fx.As causes a constructor to no longer provide its original type. The workaround we often give is for folks to do something like this, which involves adding a second "constructor":

fx.Provide(
    newConcreteType,
    func(ct *concreteType) Interface {
        return ct
    }
)

which is admittedly not very ergonomic. A somewhat common pattern mistaken to be a workaround is providing the constructor twice instead:

fx.Provide(
    newConcreteType,
    fx.Annotate(newConcreteType, fx.As(new(Interface))),
)

This PR adds fx.Self(), which returns a special value to indicate an fx.As should retain that original return type:

fx.Provide(
    newConcreteType,
    fx.As(fx.Self()),
    fx.As(new(Interface)),
)

As an alternative, I considered a new annotation altogether, named something like fx.AlsoAs, but adding a special type that can be passed as an argument to fx.As directly allows for more fine-tuned control over individual positional return values.

For example, this function's return types can be easily expressed as *asStringer and io.Writer using fx.Self():

fx.Provide(
    fx.Annotate(
        func() (*asStringer, *bytes.Buffer) {/* ... */ },
        fx.As(fx.Self(), new(io.Writer)), // return values will be: *asStringer, io.Writer
    ),
),

Whereas something like fx.AlsoAs wouldn't provide the ability to skip over the first positional return value entirely.

codecov[bot] commented 4 months ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 98.46%. Comparing base (cb9cccf) to head (afe49a5).

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #1201 +/- ## ========================================== - Coverage 98.49% 98.46% -0.03% ========================================== Files 34 34 Lines 2860 2676 -184 ========================================== - Hits 2817 2635 -182 + Misses 36 34 -2 Partials 7 7 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

JacobOaks commented 4 months ago

Changes look great and pretty isolated. Added a couple of comments.

Addressed!