Spaces group related declarations.
They are similar to TypeScript namespaces, but with a smaller surface area and a different motivation. Typical is designed for a token-based, UI-augmented editor, so spaces are both a language construct and something the editor can draw as a visual region.
The syntax is:
space App
(
space Backend
(
User
(
)
)
)
The name comes after the space keyword. This is different from the usual thing is kind shape used elsewhere in the language.
The reason is that spaces can be anonymous:
space
(
start
(
run()
)
)
Writing anonymous spaces in the normal is form would be awkward, and it would also fit poorly with how spaces are represented by the editor.
Named spaces cannot use dotted names.
This is invalid:
space App.Backend
(
)
Nested spaces must be written explicitly:
space App
(
space Backend
(
)
)
Space contents are written inside parentheses. This follows the broader language rule that parentheses are used where TypeScript-like languages would often use curly braces.
Spaces can contain the normal top-level language constructs, including imports, functions, classes, values, types, starters, declare statements, and other spaces.
space Configuration
(
import Fs
fn read(path is string) is string (
return Fs.readFileSync(path, "utf8")
)
)
Imports are ordinary members of a space. Imports in the implicit root space are visible project-wide; imports in an explicit space are visible in that space and its children.
An aliased file import creates an implicit space containing the imported file's exported top-level items:
import "Utilities.ty" as Utilities
Utilities.format()
This does not reopen or merge a declared space. It introduces one import binding whose qualified members come from the file.
Space members are not exported by default. Visibility is controlled by the visibility rules.
Names are qualified with dots.
App.Backend.User
When code inside a nested space refers to something outside that space, it must qualify the name from the appropriate visible path. When code refers to something in a completely different space, it starts from the outer visible space and drills inward.
Spaces cannot be reopened or merged.
This is invalid:
space Util
(
parse()
(
)
)
space Util
(
format()
(
)
)
All members of a space must be located in that single space declaration.
This differs from TypeScript namespaces. TypeScript supports reopening namespaces because text-file-oriented editing often needs declarations to be spread across multiple files or multiple locations. Typical does not treat raw text files as the primary editing experience. The editor can move, reveal, fold, and organize token-backed code directly, so namespace-style declaration merging is not part of the design.
Anonymous spaces provide encapsulation without adding a qualified name.
They are useful when code should be hidden away from the surrounding scope but does not deserve a public name.
space
(
loadConfig()
(
)
connect()
(
)
start
(
connect()
)
)
Anonymous spaces can appear anywhere a named space can appear, including inside other spaces.
The convention is that Spaces are expected to start with a capital letter. This is not enforced mechanically in any way. It is just a strong suggestion.
The exact Rust output strategy is not specified yet. The compiler should choose the representation that produces the most idiomatic readable Rust while preserving Typical's space boundaries and name-resolution rules.