diff --git a/.changeset/curly-horses-behave.md b/.changeset/curly-horses-behave.md
new file mode 100644
index 00000000..628ec718
--- /dev/null
+++ b/.changeset/curly-horses-behave.md
@@ -0,0 +1,8 @@
+---
+"@marko/language-server": patch
+"@marko/language-tools": patch
+"@marko/type-check": patch
+"marko-vscode": patch
+---
+
+Bound values with types
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.html b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.html
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.md b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.md
new file mode 100644
index 00000000..bc2f0ee4
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.md
@@ -0,0 +1,8 @@
+## Hovers
+### Ln 1, Col 10
+```marko
+> 1 | oneOrTwo/y
+ | ^ const y: 1 | 2
+ 2 | // ^?
+```
+
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.ts b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.ts
new file mode 100644
index 00000000..7e2f075f
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/index.ts
@@ -0,0 +1,60 @@
+export interface Input {}
+(function (this: void) {
+ const input = Marko._.any as Input;
+ const $signal = Marko._.any as AbortSignal;
+ const $global = Marko._.getGlobal(
+ // @ts-expect-error We expect the compiler to error because we are checking if the MarkoRun.Context is defined.
+ (Marko._.error, Marko._.any as MarkoRun.Context),
+ );
+ const y = Marko._.hoist(() => __marko_internal_hoist__y);
+ const __marko_internal_tag_1 = Marko._.resolveTemplate(
+ import("./tags/oneOrTwo.marko"),
+ );
+ {
+ const y = Marko._.returned(() => __marko_internal_rendered_1);
+ const __marko_internal_rendered_1 = Marko._.renderTemplate(
+ __marko_internal_tag_1 /*oneOrTwo*/,
+ )()()({
+ /*oneOrTwo*/
+ });
+ var __marko_internal_hoist__y = y;
+ }
+ Marko._.noop({ y, input, $global, $signal });
+ return;
+})();
+export default new (class Template extends Marko._.Template<{
+ render(
+ input: Marko.TemplateInput,
+ stream?: {
+ write: (chunk: string) => void;
+ end: (chunk?: string) => void;
+ },
+ ): Marko.Out;
+
+ render(
+ input: Marko.TemplateInput,
+ cb?: (err: Error | null, result: Marko.RenderResult) => void,
+ ): Marko.Out;
+
+ renderSync(input: Marko.TemplateInput): Marko.RenderResult;
+
+ renderToString(input: Marko.TemplateInput): string;
+
+ stream(
+ input: Marko.TemplateInput,
+ ): ReadableStream & NodeJS.ReadableStream;
+
+ mount(
+ input: Marko.TemplateInput,
+ reference: Node,
+ position?: "afterbegin" | "afterend" | "beforebegin" | "beforeend",
+ ): Marko.MountedTemplate;
+
+ api: "tags";
+ _(): () => <__marko_internal_input extends unknown>(
+ input: Marko.Directives &
+ Input &
+ Marko._.Relate<__marko_internal_input, Marko.Directives & Input>,
+ ) => Marko._.ReturnWithScope<__marko_internal_input, void>;
+}> {})();
+// ^?
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.html b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.html
new file mode 100644
index 00000000..e69de29b
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.md b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.md
new file mode 100644
index 00000000..ce702c27
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.md
@@ -0,0 +1,9 @@
+## Hovers
+### Ln 2, Col 10
+```marko
+ 1 |
+> 2 |
+ | ^ const x: number
+ 3 | // ^?
+```
+
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.ts b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.ts
new file mode 100644
index 00000000..42c366ff
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/__snapshots__/return-as-type.expected/tags/oneOrTwo.ts
@@ -0,0 +1,77 @@
+export interface Input {}
+function __marko_internal_template(this: void) {
+ const input = Marko._.any as Input;
+ const $signal = Marko._.any as AbortSignal;
+ const $global = Marko._.getGlobal(
+ // @ts-expect-error We expect the compiler to error because we are checking if the MarkoRun.Context is defined.
+ (Marko._.error, Marko._.any as MarkoRun.Context),
+ );
+ const x = Marko._.hoist(() => __marko_internal_hoist__x);
+ const __marko_internal_tag_1 = Marko._.resolveTemplate(
+ import("@marko/runtime-tags/tags/let.d.marko"),
+ );
+ {
+ const x = Marko._.returned(() => __marko_internal_rendered_1);
+ const __marko_internal_rendered_1 = Marko._.renderTemplate(
+ __marko_internal_tag_1 /*let*/,
+ )()()({
+ value: 1,
+ });
+ const __marko_internal_change__x = Marko._.change(
+ "x",
+ "value",
+ __marko_internal_rendered_1.return,
+ );
+ var __marko_internal_return = Marko._.returnTag({
+ value: x as 1 | 2,
+ valueChange(
+ // @ts-ignore
+ _x,
+ ) {
+ __marko_internal_change__x.x = _x;
+ },
+ });
+ var __marko_internal_hoist__x = x;
+ }
+ Marko._.noop({ x, input, $global, $signal });
+ return __marko_internal_return;
+}
+export default new (class Template extends Marko._.Template<{
+ render(
+ input: Marko.TemplateInput,
+ stream?: {
+ write: (chunk: string) => void;
+ end: (chunk?: string) => void;
+ },
+ ): Marko.Out;
+
+ render(
+ input: Marko.TemplateInput,
+ cb?: (err: Error | null, result: Marko.RenderResult) => void,
+ ): Marko.Out;
+
+ renderSync(input: Marko.TemplateInput): Marko.RenderResult;
+
+ renderToString(input: Marko.TemplateInput): string;
+
+ stream(
+ input: Marko.TemplateInput,
+ ): ReadableStream & NodeJS.ReadableStream;
+
+ mount(
+ input: Marko.TemplateInput,
+ reference: Node,
+ position?: "afterbegin" | "afterend" | "beforebegin" | "beforeend",
+ ): Marko.MountedTemplate;
+
+ api: "tags";
+ _(): () => <__marko_internal_input extends unknown>(
+ input: Marko.Directives &
+ Input &
+ Marko._.Relate<__marko_internal_input, Marko.Directives & Input>,
+ ) => Marko._.ReturnWithScope<
+ __marko_internal_input,
+ typeof __marko_internal_template extends () => infer Return ? Return : never
+ >;
+}> {})();
+// ^?
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/index.marko b/packages/language-server/src/__tests__/fixtures/script/return-as-type/index.marko
new file mode 100644
index 00000000..efe5008f
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/index.marko
@@ -0,0 +1,2 @@
+oneOrTwo/y
+ // ^?
\ No newline at end of file
diff --git a/packages/language-server/src/__tests__/fixtures/script/return-as-type/tags/oneOrTwo.marko b/packages/language-server/src/__tests__/fixtures/script/return-as-type/tags/oneOrTwo.marko
new file mode 100644
index 00000000..4df57274
--- /dev/null
+++ b/packages/language-server/src/__tests__/fixtures/script/return-as-type/tags/oneOrTwo.marko
@@ -0,0 +1,3 @@
+
+
+ // ^?
\ No newline at end of file
diff --git a/packages/language-tools/src/extractors/script/index.ts b/packages/language-tools/src/extractors/script/index.ts
index 50a0ed1f..5f8a8c54 100644
--- a/packages/language-tools/src/extractors/script/index.ts
+++ b/packages/language-tools/src/extractors/script/index.ts
@@ -954,6 +954,7 @@ constructor(_?: Return) {}
const valueLiteral = this.#read(boundRange.value);
this.#extractor
.copy(boundRange.value)
+ .write(" ")
.copy(boundRange.types)
.write(`\n)${SEP_COMMA_NEW_LINE}"`)
.copy(defaultMapPosition)