Материал FTS Structures and Types: Subject Data Shape
0%

FTS Structures and Types: Subject Data Shape

FTS Structures and Types: Subject Data Shape

This chapter is about what the utility input and morphism certificate are made of: five built-in types, optionality, named states and nesting, as well as the honest boundary of what the compiler checks automatically and what it does not.

Minimal example

категория «Счета»

  структура «Строка счёта»
    номер является строкой
    сумма является деньгами
    «срок оплаты» является датой
    просрочен является признаком
    комментарий иногда является строкой

Structure describes only observable fields. It is not a class and does not contain behavior — no methods, no constructor, no default value, except иногда является, giving a field the right to be absent.

What the compiler does

Each field in canonical JSON is a pair { name, type }. type is either one of the five built-in canonical names (Строка, Число, Дата, Деньги, Признак), or a named state name, or a name of another structure for nesting. Optionality is not a separate flag, but a suffix of the type string itself: Строка | undefined. Further, it is this string that is read by executeUtility (runtime input check), generateTypeScript (mapping to TS) and any third-party form adapter — all three use the same field text, not the parser tokens.

Built-in types

FTS Canonical Type JavaScript
является строкой Строка string
является числом Число number
является датой Дата ISO string on the boundary
является деньгами Деньги finite number in current runtime
является признаком Признак boolean
иногда является … T | undefined field may be absent

Дата at runtime check level is just a string: executeUtility distinguishes it from Строка only in the canonical model, not at the moment of execution, so "вчера" will pass the type check just as easily as "2026-08-03". Parsing and validation of calendar date is the application’s task. Деньги is also a regular finite number (Number.isFinite, without -0); for currency precision, the production application should choose minor units or a decimal adapter in advance, FTS does not magically fix IEEE 754.

There is also a less obvious boundary: if after “is” there is a word that is not in this table and does not start with “state”, the compiler will not reject it. The line валюта является Валюта compiles without errors — “Currency” becomes a tag type, even if a structure with such a name is declared nowhere. Checks that an arbitrary field type refers to an existing structure are absent in validate; this distinguishes such a field from вложен объект, where the name is simultaneously a type and (by convention, not by compiler enforcement) a reference to another model structure.

State is not a nested structure

объект Заказ
  «готов к отгрузке» является состоянием «Готов к отгрузке»

The canonical type of such a field is not a wrapper like Состояние, but literally the name of the state itself: "type": "Готов к отгрузке". Thus, the domain of the morphism «Готовый заказ можно отгрузить» (line если «Готов к отгрузке») coincides with the type of the field directly, without an intermediate stage. This is precisely why replacing the state with a structure does not work: the structure has no concept of “valid transition”, and the morphism cannot compare itself to a list of fields — they speak different languages of the canonical model, even though they live in the same JSON.

If an object really has composite data — not one state value, but several fields together — use nesting:

объект Заказ
  вложен объект «Адрес доставки»

The type of such a field is the name of a nested structure (“Shipping Address”). The compiler does not automatically expand the fields of a nested structure into the parent: the adapter that builds a form or a table will have to find the structure with this name in document.structures itself, if its fields are needed, not just the name.

What does the structure turn into

compile(source) returns an array structures. The adapter can turn fields into UI without re-enumeration:

const controls = document.structures
  .find(({ name }) => name === "Строка счёта")
  .fields.map((field) => ({
    name: field.name,
    required: !field.type.includes("undefined"),
    control: field.type === "Признак" ? "checkbox" : "text",
  }))

This does not mean that FTS knows the entire form design. Layout, hints, async validation and availability remain the responsibility of the UI component. FTS eliminates duplication of names, types and requiredness.

How types get into TypeScript

generateTypeScript reads the structure bound to the utility as принимает, and for each field calls the same mapping function as the runtime check: Строка/Датаstring, Число/Деньгиnumber, Признакboolean, the suffix | undefined is preserved as is. If the field type is a name of a state or an arbitrary label like «Currency» from the example above, the generator does not crash but also does not guess: it honestly outputs unknown. This is expected — utilities in FTS accept flat scalar structures, not objects with states; a state field in a structure used by a utility almost always indicates that the model mixes two different tasks (computation and output) in one object.

Practice in the sandbox

Find the «готов к отгрузке» field in the Заказ JSON structure. Its type must literally match the «то» string in the «Готовый заказ можно отгрузить» morphism.

Open FtsInput0 in the generated code. Count how many fields became number, and how many — boolean (the correct answer: three and one). Note that вес and расстояние are different units of measurement, but the compiler sees both simply as Число.

Replace «state» with «state» in one place (remove the last letter). Obtain the diagnostics FTS_NATURAL_FIELD and return the text back.

Common Fallacies

FTS_NATURAL_FIELD — field line does not match the form «имя» является типом or «имя» иногда является типом. The missing word “is” — a common cause: сумма деньгами instead of сумма является деньгами gives exactly this diagnostic with the line number. Fix — return the keyword является/иногда является between the field name and the type.

FTS_UTILITY_PROPERTY — property utility violated on a specific example. The property does not fix the result automatically: if the rule adds 200% instead of the declared maximum of 20% in the postcondition, testUtilities will mark the example as failed with this code in the error message, and a direct call executeUtility will throw it as diagnostics. Fix — correct either the rule, or (if the rule is correct, but the limit is outdated) the property text itself; both require a deliberate decision, not number tweaking.

Checklist

  • I know five built-in types and that Дата and Деньги are checked at runtime more leniently than their names suggest.
  • I can explain the difference between a state field and a field — an embedded object.
  • I understand that a field type with an arbitrary word after «is» is not checked for the existence of the corresponding structure.
  • I can predict what each field of a structure will become in the generated TypeScript.

Cases in the catalog on this topic

Next: executable utilities

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов
Дальше