The @types block
Declaring a template's interface.
A @types block is the template’s function signature, written in a comment — it works with plain Edge, requires zero runtime changes, and can never affect rendering. The body is an object literal or any TypeScript type expression.
{{--
@types {
user: { name: string, email: string }
posts: { title: string, body: string }[]
}
--}}The common case: declare the props right where they’re used.
The body accepts any TypeScript type expression, so shared shapes live in real .ts files:
{{-- @types import('./shared/layout.types.ts').Props --}}export interface Props {
user: { name: string; avatarUrl: string }
nav: { label: string; href: string }[]
}Best once several templates share a shape — one interface, many templates.
Imports resolve through your project’s tsconfig.json, so path aliases work — including framework models:
{{-- @types { user: import('#models/user').User } --}}
The doc header: @name and @desc
The same comment can carry documentation — JSDoc for templates. @name takes the rest of its line; @desc runs until the next directive or the comment’s end:
{{--
@name User Card
@desc Displays a user card with title and body.
Used on the profile and team pages.
@types {
user: { name: string }
}
--}}
Editors surface all three together: hover @userCard (or the path string in @component('components/user_card', ...)) anywhere it’s used and you get the name, the description, and the props signature. The same card appears in the @ tag-completion popup, so a component library documents itself as you browse. Stock Edge ignores comments, so none of this touches rendering.
What’s inferred (never declared)
@let(total = items.length * 2)—total: number@each(item in items)—itemfrom the array’s element type- Narrowing inside
@if(user.subscription)blocks - Edge globals (
truncate,html.escape, case helpers, …) are pre-typed
Cross-file checking
@component('components/card', { title })— the props object is checked against the component’s own@types; typos error at the caller- Supercharged shorthands (
@formInput(...),@modal(...)) resolve through Edge’s filename-to-tag rules and get the same checking @include('partials/nav')— the caller’s state must satisfy the partial’s declared types- Dynamic names (
@include(someVar)) degrade gracefully to unchecked