Skip to content

Type Annotations

starlark-go-x extends the standard Starlark parser to support Python-style type annotations. These annotations are parsed and stored in the AST but are not enforced at runtime.

def greet(name: str) -> str:
return "Hello, " + name
def add(a: int, b: int = 0) -> int:
return a + b
def process(items: list, callback: callable) -> None:
for item in items:
callback(item)
def transform(data: dict[str, list[int]]) -> list[str]:
results = []
for key, values in data.items():
results.append("{}: {}".format(key, sum(values)))
return results
def find(items: list[str], predicate: callable) -> str | None:
for item in items:
if predicate(item):
return item
return None
# Variable type hints (parsed but not enforced)
config: dict[str, str] = {}
count: int = 0
items: list[str] = ["a", "b", "c"]

The parser introduces new AST node types for type annotations:

Wraps a type expression (identifier or parameterized type).

type TypeExpr struct {
Name *Ident // Base type name (e.g., "list", "dict", "str")
Params []*TypeExpr // Type parameters (e.g., [str] for list[str])
}

Parameters with type annotations store the annotation in the AST:

type Param struct {
Name *Ident // Parameter name
Type *TypeExpr // Type annotation (nil if not annotated)
Default Expr // Default value (nil if required)
}

Function definitions store the return type:

type DefStmt struct {
Name *Ident
Params []*Param
ReturnType *TypeExpr // Return type annotation (nil if not annotated)
Body []Stmt
}

Type annotations are disabled by default. Enable them via FileOptions:

import (
"go.starlark.net/syntax"
)
func parseWithTypes(filename string, src []byte) (*syntax.File, error) {
opts := &syntax.FileOptions{
TypeAnnotations: true,
}
return opts.Parse(filename, src, 0)
}

Or when using starlark.ExecFile:

import (
"go.starlark.net/starlark"
"go.starlark.net/syntax"
)
func execWithTypes(filename string, src []byte) (starlark.StringDict, error) {
opts := &syntax.FileOptions{
TypeAnnotations: true,
}
_, program, err := starlark.SourceProgramOptions(opts, filename, src, nil)
if err != nil {
return nil, err
}
thread := &starlark.Thread{Name: "main"}
return program.Init(thread, nil)
}

Extract type information for documentation:

func documentFunction(fn *syntax.DefStmt) string {
var params []string
for _, p := range fn.Params {
if p.Type != nil {
params = append(params, fmt.Sprintf("%s: %s", p.Name.Name, typeString(p.Type)))
} else {
params = append(params, p.Name.Name)
}
}
ret := ""
if fn.ReturnType != nil {
ret = " -> " + typeString(fn.ReturnType)
}
return fmt.Sprintf("def %s(%s)%s", fn.Name.Name, strings.Join(params, ", "), ret)
}
func typeString(t *syntax.TypeExpr) string {
if len(t.Params) == 0 {
return t.Name.Name
}
var params []string
for _, p := range t.Params {
params = append(params, typeString(p))
}
return fmt.Sprintf("%s[%s]", t.Name.Name, strings.Join(params, ", "))
}

Check for type consistency (custom linter):

func checkTypeAnnotations(f *syntax.File) []error {
var errors []error
syntax.Walk(f, func(n syntax.Node) bool {
if def, ok := n.(*syntax.DefStmt); ok {
// Check that all parameters are annotated (or none)
annotated := 0
for _, p := range def.Params {
if p.Type != nil {
annotated++
}
}
if annotated > 0 && annotated < len(def.Params) {
errors = append(errors, fmt.Errorf(
"%s: partial type annotations (annotate all parameters or none)",
def.Name.Name,
))
}
}
return true
})
return errors
}

Provide type information for hover and completion:

func getTypeAtPosition(f *syntax.File, line, col int) *syntax.TypeExpr {
var result *syntax.TypeExpr
syntax.Walk(f, func(n syntax.Node) bool {
pos := n.Span()
if pos.Start.Line == int32(line) {
if param, ok := n.(*syntax.Param); ok && param.Type != nil {
result = param.Type
return false
}
}
return true
})
return result
}

For full type checking, consider:

  • Using starlark-rust which has experimental static type checking
  • Building a custom type checker using the AST information
  • Waiting for the upstream starlark spec to standardize types
Featurestarlark-go-xstarlark-ruststarlark-java
Parse annotationsYesYesYes
Runtime checkingNoPartialPartial
Static checkingNoExperimentalWIP
Generic typesParse onlyFull supportNo
Union typesParse onlyFull supportNo
Record typesNoYesNo

Type annotation support in starlark-go-x is designed to enable tooling. Future enhancements may include:

  1. Upstream contribution - Propose annotation parsing to google/starlark-go
  2. Type inference - Infer types from usage patterns
  3. Static checker - Optional compile-time type verification
  4. Type stub files - Define types for external modules