SwiftUI is well-designed. It's also ceremony-heavy. A simple form view needs @State, @FocusState, @Environment, view builders, and about thirty lines of code before you've written any business logic.
Axint's defineView() lets you describe the structure in TypeScript and get a real SwiftUI struct back. Not a wrapper. Not a runtime library. A .swift file you can open, read, and modify.
const userDetails = defineView({
name: "UserDetailsView",
state: {
user: "User",
isEditing: "Bool",
},
body: [
{
type: "VStack",
spacing: 16,
children: [
{ type: "Text", text: "{{ user.name }}", font: "headline" },
{ type: "Button", label: "Edit", action: "toggleEditing()" },
],
},
],
});Compiles to:
struct UserDetailsView: View {
@State var user: User
@State var isEditing: Bool
var body: some View {
VStack(spacing: 16) {
Text(user.name)
.font(.headline)
Button("Edit") {
toggleEditing()
}
}
}
private func toggleEditing() {
isEditing.toggle()
}
}Complete, compilable, correct. The TypeScript tree mirrors the SwiftUI tree structurally, so the mapping is direct — no "lowest common denominator" abstraction.
When this makes sense
It's not about replacing SwiftUI. If you're building a complex custom layout with gestures and animations, write that in Swift. defineView() is for the other 80% — the CRUD screens, the settings pages, the list-detail views that are structurally identical across every app.
200 views in an app. Most of them are mechanical. When your API response shape changes, update one TypeScript definition and recompile. All your views stay in sync.
Ejecting
The generated Swift has no magic. No special imports, no Axint runtime dependency. If you need custom logic — a gesture handler, a complex animation — open the .swift file and add it. The generated code is your starting point, not a lock-in.
We're adding @Binding support, form validation codegen, and custom view modifiers next. The goal by WWDC: define entire app screens in TypeScript, compile to production SwiftUI. More on the timeline in the roadmap post.