Swift and SwiftUI for Web Developers Introduction
Jumping from web development into lower-level languages like Swift can seem a bit intimidating. But Swift, especially Swift 6 along with SwiftUI, turns out to be surprisingly approachable and useful for front-end developers — and it’s not all about crafting applications for Apple devices. Swift can sometimes be a good choice even in scenarios where one might typically consider Rust for its performance advantages.
In this first post, we’re diving into why Swift might just be the secret weapon for web developers looking to level up their coding game. I’ll share insights into the aspects of Swift that stood out to me initially. We’ll also explore its similarities to TypeScript, which makes it particularly easy to learn for web developers.
Compatibility and Uses
Before we begin, let’s address the elephant in the room: yes, Swift is developed by Apple, and a significant usage of Swift is to write native Apple apps with SwiftUI. However, Swift is a perfectly valid solution for writing any application code, from web servers and command-line tools to code for embedded devices. It is open-source, has support in IDEs like VSCode, IntelliJ, Neovim, etc., and can be run and built on macOS, Windows, and Linux.
Swift looks a lot like TypeScript
If you’re accustomed to writing TypeScript, you’ll quickly feel at home with Swift.
Here’s an example of defining a variable in Swift:
let name: String = "Pausly"
Notice how the type is added after a colon (:
).
Semicolons (;
) at the end of a statement are optional in both languages and
usually aren’t added.
Like TypeScript, Swift boasts an impressive type system capable of inferring types in many cases, making code easier to write and read:
// Exactly the same as the previous example.
// The type of `name` is inferred to be `String`.
let name = "Pausly"
Swift utilizes let
and var
for declaring constants and variables,
respectively, contrasting with TypeScript’s const
and let
:
var
is used for variables that can change.let
is for constants that are immutable.
Support for string interpolation exists in Swift, albeit with slightly different syntax:
let name = "Pausly"
let greeting = "Hello \(name)"
Function definitions also bear similarity with minor syntax differences:
func greeting(name: String) -> String {
return "Hello \(name)"
}
A convenient feature is that functions containing only a single expression implicitly return that expression, simplifying the previous example to:
func greeting(name: String) -> String { "Hello \(name)" }
In Part 2 of this series, I’ll delve into Swift Closures, highlighting the elegant methods for defining closures in Swift.
Arrays and other collections in Swift are straightforward, with slight syntax
variations from TypeScript. For example, an array of strings in TypeScript
string[]
corresponds with [String]
in Swift. Coming from TypeScript, the
Swift syntax looks like the tuple syntax, but Swift has it’s own
tuple type
and doesn’t need to abuse the array for that functionality.
func greeting(names: [String]) -> String {
"Hello \(names.joined(separator: ", "))"
}
// Tuples:
func getCoordinates() -> (Int, Int) {
(10, 20)
}
Swift’s APIs are thoughtfully designed, using the passive voice for methods that
return modified versions of objects rather than modifying the objects
themselves, just like the .joined()
method we used above.
Control flow
Control structures such as If, Switch, and For share a strong resemblance with TypeScript. Here are a few examples that don’t need much explanation:
// Parentheses around conditions are not required
if age < 18 {
throw BounceError.tooYoung(requiredAge: 18)
}
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
switch someCharacter {
case "a":
print("The first letter of the Latin alphabet")
case "z":
print("The last letter of the Latin alphabet")
default:
print("Some other character")
}
Asynchronous Programming
While the examples provided thus far have been relatively straightforward, Swift’s syntax remains familiar even when delving into more complex concepts, such as asynchronous functions:
func getNames() async -> [String] {
let users = await listUsers()
return users.map { $0.name }
}
- Functions are declared as async using the
async
keyword. - In Swift you don’t need to wrap the return type in as you do in TypeScript
Promise<string[]>
. - The
await
keyword pauses execution until the asynchronous task is complete, akin to TypeScript. - The last line shows Swift’s closure syntax. We’ll learn more about in the next post.
Conclusion
This overview briefly introduces Swift’s basic features, showcasing its similarity to TypeScript and the familiar, comfortable feeling it offers. Of course, there’s much more to Swift, which I’ll explore in subsequent parts of this series.
Need a Break?
I built Pausly to help people like us step away from the screen for just a few minutes and move in ways that refresh both body and mind. Whether you’re coding, designing, or writing, a quick break can make all the difference.
Give it a try