Перечисления
Автоматическое создание перечислений из констант Go
Привязки перечислений
Генератор привязок Wails v3 автоматически обнаруживает типы констант Go и создаёт перечисления TypeScript или объекты const JavaScript. Не требуется ни регистрация, ни настройка: просто определите типы и константы в Go, а генератор сделает всё остальное.
Быстрый старт
Определите в Go именованный тип с константами:
type Status string
const (
StatusActive Status = "active"
StatusPending Status = "pending"
StatusClosed Status = "closed"
)Используйте этот тип в структуре или методе сервиса:
type Ticket struct {
ID int `json:"id"`
Title string `json:"title"`
Status Status `json:"status"`
}Создайте привязки:
wails3 generate bindings
В выводе генератора количество перечислений будет указано рядом с количеством моделей:
3 Enums, 5 ModelsИспользуйте во фронтенде:
import { Ticket, Status } from './bindings/changeme/models'
const ticket = new Ticket({
id: 1,
title: "Bug report",
status: Status.StatusActive
})Вот и всё! Тип перечисления проверяется как в Go, так и в JavaScript/TypeScript.
Определение перечислений
Перечисление в Wails — это именованный тип с базовым простым типом в сочетании с объявлениями const этого типа.
Строковые перечисления
// Title is a title
type Title string
const (
// Mister is a title
Mister Title = "Mr"
Miss Title = "Miss"
Ms Title = "Ms"
Mrs Title = "Mrs"
Dr Title = "Dr"
)Созданный код TypeScript:
/**
* Title is a title
*/
export enum Title {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Mister is a title
*/
Mister = "Mr",
Miss = "Miss",
Ms = "Ms",
Mrs = "Mrs",
Dr = "Dr",
}Созданный код JavaScript:
/**
* Title is a title
* @readonly
* @enum {string}
*/
export const Title = {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero: "",
/**
* Mister is a title
*/
Mister: "Mr",
Miss: "Miss",
Ms: "Ms",
Mrs: "Mrs",
Dr: "Dr",
};Целочисленные перечисления
type Priority int
const (
PriorityLow Priority = 0
PriorityMedium Priority = 1
PriorityHigh Priority = 2
)Созданный код TypeScript:
export enum Priority {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = 0,
PriorityLow = 0,
PriorityMedium = 1,
PriorityHigh = 2,
}Перечисления на основе псевдонимов типов
Псевдонимы типов Go (=) также поддерживаются, но для них создаётся немного другой код: определение типа и объект const вместо собственного enum TypeScript:
// Age is an integer with some predefined values
type Age = int
const (
NewBorn Age = 0
Teenager Age = 12
YoungAdult Age = 18
// Oh no, some grey hair!
MiddleAged Age = 50
Mathusalem Age = 1000 // Unbelievable!
)Созданный код TypeScript:
/**
* Age is an integer with some predefined values
*/
export type Age = number;
/**
* Predefined constants for type Age.
* @namespace
*/
export const Age = {
NewBorn: 0,
Teenager: 12,
YoungAdult: 18,
/**
* Oh no, some grey hair!
*/
MiddleAged: 50,
/**
* Unbelievable!
*/
Mathusalem: 1000,
};Созданный код JavaScript:
/**
* Age is an integer with some predefined values
* @typedef {number} Age
*/
/**
* Predefined constants for type Age.
* @namespace
*/
export const Age = {
NewBorn: 0,
Teenager: 12,
YoungAdult: 18,
/**
* Oh no, some grey hair!
*/
MiddleAged: 50,
/**
* Unbelievable!
*/
Mathusalem: 1000,
};Значение $zero
Каждое перечисление на основе именованного типа содержит специальный элемент $zero, представляющий нулевое значение Go для базового типа:
| Базовый тип | Значение $zero |
|---|---|
string |
"" |
int, int8, int16, int32, int64 |
0 |
uint, uint8, uint16, uint32, uint64 |
0 |
float32, float64 |
0 |
bool |
false |
Если поле структуры имеет тип перечисления и значение не задано, конструктор по умолчанию использует $zero:
export class Person {
"Title": Title;
constructor($$source: Partial<Person> = {}) {
if (!("Title" in $$source)) {
this["Title"] = Title.$zero; // defaults to ""
}
Object.assign(this, $$source);
}
}Это обеспечивает типобезопасную инициализацию при создании классов: поля перечислений никогда не имеют значения undefined. При создании интерфейсов TypeScript (с использованием -i) конструктора нет, поэтому поля, как обычно, могут отсутствовать.
Использование перечислений в структурах
Если поле структуры имеет тип перечисления, созданный код сохраняет этот тип, а не заменяет его простым типом:
type Person struct {
Title Title
Name string
Age Age
}Созданный код TypeScript:
export class Person {
"Title": Title;
"Name": string;
"Age": Age;
constructor($$source: Partial<Person> = {}) {
if (!("Title" in $$source)) {
this["Title"] = Title.$zero;
}
if (!("Name" in $$source)) {
this["Name"] = "";
}
if (!("Age" in $$source)) {
this["Age"] = 0;
}
Object.assign(this, $$source);
}
}Поле Title имеет тип Title, а не string. Благодаря этому IDE обеспечивает полноценное автодополнение и проверку типов для значений перечисления.
Перечисления из импортированных пакетов
Перечисления, определённые в отдельных пакетах, полностью поддерживаются. Код для них создаётся в каталоге соответствующего пакета:
// services/types.go
package services
type Title string
const (
Mister Title = "Mr"
Miss Title = "Miss"
Ms Title = "Ms"
)// main.go
package main
import "myapp/services"
func (*GreetService) Greet(name string, title services.Title) string {
return "Hello " + string(title) + " " + name
}Перечисление Title создаётся в файле моделей services, а пути импорта определяются автоматически:
// bindings/changeme/services/models.ts
export enum Title {
$zero = "",
Mister = "Mr",
Miss = "Miss",
Ms = "Ms",
}Методы перечислений
К типам перечислений в Go можно добавлять методы. Они не влияют на создание привязок, но предоставляют полезные возможности на стороне сервера:
type Title string
func (t Title) String() string {
return string(t)
}
const (
Mister Title = "Mr"
Miss Title = "Miss"
)Созданное перечисление будет одинаковым независимо от наличия у типа методов Go.
Комментарии и документация
Генератор сохраняет комментарии Go в созданном коде в формате JSDoc:
- Комментарии к типам становятся документирующими комментариями к перечислениям
- Комментарии к группам констант становятся разделителями секций
- Комментарии к отдельным константам становятся документирующими комментариями к элементам
- Встроенные комментарии сохраняются, где это возможно
Благодаря этому IDE показывает документацию для значений перечисления при наведении указателя.
Поддерживаемые базовые типы
Генератор привязок поддерживает перечисления со следующими базовыми типами Go:
| Тип Go | Поддерживается как перечисление |
|---|---|
string |
Да |
int, int8, int16, int32, int64 |
Да |
uint, uint8, uint16, uint32, uint64 |
Да |
float32, float64 |
Да |
byte (uint8) |
Да |
rune (int32) |
Да |
bool |
Да |
complex64, complex128 |
Нет |
Ограничения
При создании перечислений не поддерживаются:
- Обобщённые типы — параметры типов препятствуют обнаружению констант
- Типы с пользовательскими
json.Marshalerилиencoding.TextMarshaler— при пользовательской сериализации сгенерированные значения могут не соответствовать поведению во время выполнения, поэтому генератор пропускает такие типы - Константы, значения которых невозможно вычислить статически или представить — значения констант должны быть известны и представимы в их базовом типе. Стандартные шаблоны
iotaработают корректно, поскольку компилятор преобразует их в конкретные значения - Типы комплексных чисел —
complex64иcomplex128не могут быть базовыми типами перечислений
Полный пример
Go:
package main
import (
"github.com/wailsapp/wails/v3/pkg/application"
)
// BackgroundType defines the type of background
type BackgroundType string
const (
BackgroundSolid BackgroundType = "solid"
BackgroundGradient BackgroundType = "gradient"
BackgroundImage BackgroundType = "image"
)
type BackgroundConfig struct {
Type BackgroundType `json:"type"`
Value string `json:"value"`
}
type ThemeService struct{}
func (*ThemeService) GetBackground() BackgroundConfig {
return BackgroundConfig{
Type: BackgroundSolid,
Value: "#ffffff",
}
}
func (*ThemeService) SetBackground(config BackgroundConfig) error {
// Apply background
return nil
}
func main() {
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&ThemeService{}),
},
})
app.Window.New()
app.Run()
}Фронтенд (TypeScript):
import { GetBackground, SetBackground } from './bindings/changeme/themeservice'
import { BackgroundConfig, BackgroundType } from './bindings/changeme/models'
// Get current background
const bg = await GetBackground()
// Check the type using enum values
if (bg.type === BackgroundType.BackgroundSolid) {
console.log("Solid background:", bg.value)
}
// Set a new background
await SetBackground(new BackgroundConfig({
type: BackgroundType.BackgroundGradient,
value: "linear-gradient(to right, #000, #fff)"
}))Фронтенд (JavaScript):
import { GetBackground, SetBackground } from './bindings/changeme/themeservice'
import { BackgroundConfig, BackgroundType } from './bindings/changeme/models'
// Use enum values for type-safe comparisons
const bg = await GetBackground()
switch (bg.type) {
case BackgroundType.BackgroundSolid:
applySolid(bg.value)
break
case BackgroundType.BackgroundGradient:
applyGradient(bg.value)
break
case BackgroundType.BackgroundImage:
applyImage(bg.value)
break
}Дальнейшие шаги
Структуры, сопоставление типов и создание моделей.
Привязка методов Go к фронтенду.
Директивы, внедрение кода и пользовательские идентификаторы.
Шаблоны проектирования привязок.
Есть вопросы? Задайте их в Discord или ознакомьтесь с примерами привязки.