Skip to content

Allow field access on concrete types behind interface values #951

@snaffi

Description

@snaffi

Summary

  • Allow property access on typed interface values by deferring field resolution to runtime, where the
    concrete type can be inspected
  • At runtime, recursively traverse embedded interface fields to find properties on the underlying concrete
    struct (e.g. Proxy → *Wrapper → Node(interface) → *Container → Items)
  • Method calls on interfaces without the method still produce compile-time errors

Motivation

When a method returns a typed interface (e.g. GetByID() Component), accessing fields on the concrete type behind that interface (result.Content) was rejected by the checker since the interface type has no such field.
This change defers property lookups on interface types to runtime, where reflection can inspect the actual value.

Real life issue

// Domain types (simplified)
type Component interface {
	ID() string
}

type Header struct {
	CompID string
}

func (h Header) ID() string { return h.CompID }

type WidgetCarouselV2 struct {
	Header
	Content []*Widget
}

type Widget struct {
	Id string
}

type LoadingOrganism struct {
	Component // embedded interface
}

type AsyncComponent struct {
	*LoadingOrganism
}

type Components []Component

func (cs Components) GetByID(id string) Component {
	for _, c := range cs {
		if c.ID() == id {
			return c
		}
	}
	return nil
}

func main() {
	c := &AsyncComponent{
		LoadingOrganism: &LoadingOrganism{
			Component: &WidgetCarouselV2{
				Header:  Header{CompID: "hero-carousel"},
				Content: []*Widget{{Id: "promo-1"}},
			},
		},
	}

	// Before: fails with "cannot fetch Content from *domain.AsyncComponent"
	// After:  returns "promo-1"
	output, err := expr.Eval(
		`data.GetByID("hero-carousel")?.Content[0].Id`,
		map[string]any{"data": Components{c}},
	)

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions