Типы позволяют проверяющему ответить до запуска программы на практический вопрос: какие значения разрешено передавать через эту границу? Для большинства локальных значений тип писать не нужно. Аннотация полезна там, где она поясняет важный вход, результат или выбор предметной области.
Начните с одной проверяемой программы
Сохраните этот код в файле types.tpz:
type Stage = "draft" | "ready"
function describe(stage: Stage, checks: int) -> string {
"{stage} after {checks} checks"
}
let checks = 3
let current: Stage = "ready"
let render: (Stage, int) -> string = describe
print(render(current, checks))Сначала проверьте границы типов, затем запустите программу:
topaz check types.tpz
topaz run types.tpz
Результат:
ready after 3 checksПрочитайте типы по коду и результату
У checks нет аннотации. Начальное значение — целое число, поэтому Топаз выводит тип int. У current аннотация есть: программе требуется именно Stage, а не любая строка string.
Stage — прозрачный псевдоним для объединения литералов "draft" | "ready". Такое объединение разрешает одно из двух перечисленных значений и отклоняет любую другую строку. Псевдоним даёт выбору понятное имя, но не создаёт отдельной сущности во время выполнения.
У render указан тип функции. Запись (Stage, int) -> string означает «функция принимает Stage и int, а возвращает string». Именованная функция describe имеет именно такую форму, поэтому её можно сохранить в связывании и вызвать позднее.
Названия базовых типов пишутся строчными буквами: int, float, bool, string и единичный тип (). Для контейнеров используются именованные конструкторы Array<T>, Map<K, V> и Set<T>. Ожидаемое отсутствие значения выражается через Option<T>, а восстанавливаемая ошибка — через Result<T, E>.
Выберите форму, которая передаёт намерение
| Задача | Что выбрать | Почему |
|---|---|---|
| Очевидное локальное значение | Вывод типа | Начальное значение уже ясно показывает тип. |
| Публичный вход, результат или важная локальная граница | Аннотацию | Проверяющий и читатель сразу видят задуманный контракт. |
| Одно значение из закрытого набора вариантов | Объединение или псевдоним объединения литералов | Все допустимые варианты перечислены явно. |
| Значение, которое позже будут вызывать | Тип функции, например (int) -> bool | Типы параметров и результата хранятся вместе с функцией. |
| Самостоятельная сущность предметной области, поля или именованные варианты | record, enum или newtype | Номинальные объявления остаются разными, даже если устроены похоже. |
Псевдоним type делает код понятнее, но остаётся прозрачным. Если смешение двух похожих по форме значений было бы настоящей ошибкой, выбирайте номинальные данные. На странице Записи и номинальные данные сопоставлены создание и сопоставление для record, enum и newtype.
Дайте пустому значению контекст
Некоторые значения сами по себе не сообщают достаточно сведений. Пустой массив не показывает тип элемента, а None — тип отсутствующего значения. Контекст можно задать аннотацией, параметром функции, объявленным результатом или окружающим типом:
let names: Array<string> = []
let selected: Option<int> = NoneЗдесь канонические формы показаны как текст. Проверяемой программой этой страницы остаётся полный пример выше.
Частая ошибка: перенос записи типов из целевого языка
Типы коллекций Топаза записываются как Array<T>, Map<K, V> и Set<T>. В типе функции параметры заключаются в круглые скобки, после чего -> отделяет тип результата. Единая запись помогает проверяющему и создаваемым целевым программам опираться на один исходный контракт.
Точные ограничения
- Между
intиfloatнет неявного преобразования. - Параметры обобщённых типов инвариантны: разные аргументы типов не становятся совместимыми лишь из-за сходства содержимого.
- Ограничения обобщённого типа допускаются только у параметров именованной функции. Разрешённая форма первого ранга описана на странице Функции и обобщения.
- Рекурсивные псевдонимы, аннотации вариантности, полиморфизм высших рангов и более широкая рефлексия пока отложены.
- Если контекст так и не определил параметры пустого обобщённого значения, это статическая ошибка, а не повод угадывать тип во время выполнения.
Если вывод типов, аннотации и изменяемость ещё непривычны, вернитесь к уроку Значения и функции. Выбор между отсутствием, восстанавливаемой ошибкой и сбоем разобран на странице Null, Option, Result и ошибки.