How to Understand TypeScript Types, Swift Structs and Other Concepts

TypeScript vs Swift illustration

Recently, I started using both Swift and TypeScript daily for different projects. This made me think about leveraging my existing knowledge to understand new concepts in each language, as I’m still learning both. As a developer, you might need to learn multiple programming languages, so understanding their similarities and differences can ease your transition and enhance your versatility. This post will compare core concepts in TypeScript and Swift, providing clear explanations.

TypeScript, a statically typed superset of JavaScript, introduces type definitions to improve code quality. We’ll explore three fundamental concepts today: type, interface, and class. Swift, used for iOS and macOS development, shares some similarities with TypeScript but also has unique features. Comparing these concepts in both languages helped me understand them better.

When coding in TypeScript my biggest question was (in regards to today’s topic): What is the difference between types and interfaces? For a straightforward introduction to TypeScript types and interfaces without Swift, here’s a helpful YouTube video I recently came across:

Comparison of types and interfaces in TypeScript

On the other hand when I am coding with Swift the same question sounds like this: What is the difference between classes and structs? I have a handy video prepared for answering this question as well:

Comparison of classes and structs in Swift

TypeScript Types

The type keyword in TypeScript is a versatile feature used to define custom types. It can create aliases for primitive types, complex object types, union types, intersection types, and more. This flexibility allows you to create reusable and descriptive types, enhancing code readability and type safety.

// Primitive Type Alias: basic data type
// ID can be either a string or a number, making it easier to manage variables that can hold both types.
type ID = string | number;


// Object Type: structured data type composed of key-value pairs
// This defines Point as an object type with x and y properties, both of which are numbers. This can be particularly useful when dealing with coordinates in a 2D space.
type Point = {
  x: number;
  y: number;
};


// Union Type:  hold values of different specified types
// The Status type can be one of the specified string literals, making it easy to handle different states of an operation.
type Status = "success" | "failure" | "pending";


// Intersection Type: combines multiple types into one
// This combines the properties of Name and Contact into a single type Person, which includes both personal and contact information.
type Name = {
  firstName: string;
  lastName: string;
};

type Contact = {
  email: string;
  phone: string;
};

type Person = Name & Contact;

Swift Struct & Typealias

In Swift, similar functionality can be achieved using structenum, and typealias.

// Struct: For defining object-like structures.
// This defines a Point struct with x and y properties.
struct Point {
    var x: Int
    var y: Int
}


// Typealias: For creating type aliases.
// This creates a type alias ID that can be either String or Int, using a custom Either enum to handle the union type.
typealias ID = Either<String, Int>

enum Either<T, U> {
    case first(T)
    case second(U)
}

TypeScript Interfaces

An interface in TypeScript defines the shape of an object. It specifies the types of properties an object should have and can also describe function types. Interfaces can extend other interfaces, making them reusable and extendable.

// Basic Interface: outlines the structure that an object should follow
// This interface defines Point with x and y properties, both of which are numbers. Any object implementing this interface must adhere to this structure.
interface Point {
  x: number;
  y: number;
}


// Interface for Function Type: defines the expected signature of a function
// SearchFunc is an interface for a function that takes two string parameters and returns a boolean. This can be useful for type-checking functions.
interface SearchFunc {
  (source: string, subString: string): boolean;
}


// Extending Interfaces: allows one interface to inherit properties from another
// Square extends Shape, adding a sideLength property. This allows for a clear and concise definition of related interfaces.
interface Shape {
  color: string;
}

interface Square extends Shape {
  sideLength: number;
}

Swift Protocol

In Swift, protocol serves a similar purpose to TypeScript’s interface, defining a blueprint for methods, properties, and other requirements for a particular task or piece of functionality.

// Protocol Definition
// This defines a Drawable protocol with a draw method that conforming types must implement.
protocol Drawable {
    func draw()
}


// Struct Conforming to Protocol
// This Point struct conforms to the Drawable protocol, implementing the draw method.
struct Point: Drawable {
    var x: Int
    var y: Int

    func draw() {
        print("Drawing point at (\(x), \(y))")
    }
}

TypeScript Classes

class in TypeScript is a blueprint for creating objects with specific properties and methods. Classes support inheritance, allowing one class to extend another. They can also implement interfaces to enforce a specific structure or behavior.

// Basic Class
// This Point class includes properties x and y and a move method to change the point's position.
class Point {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }

  move(dx: number, dy: number): void {
    this.x += dx;
    this.y += dy;
  }
}


// Class Inheritance
// Dog extends Animal, overriding the makeSound method to provide a specific implementation.
class Animal {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  makeSound(): void {
    console.log("Some generic sound");
  }
}

class Dog extends Animal {
  makeSound(): void {
    console.log("Bark");
  }
}


// Class Implementing Interface
// The Square class implements the draw method as required by the Drawable interface, ensuring it adheres to the contract.
interface Drawable {
  draw(): void;
}

class Square implements Drawable {
  draw() {
    console.log("Drawing a square");
  }
}

Swift Classes

In Swift, classes are similar to those in TypeScript. They are used to create objects with properties and methods and support inheritance.

// Basic Class
// This Point class has properties x and y and a move method to update the point's position.
class Point {
    var x: Int
    var y: Int

    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }

    func move(dx: Int, dy: Int) {
        self.x += dx
        self.y += dy
    }
}


// Class Inheritance
// The Dog class extends Animal, overriding the makeSound method.
class Animal {
    var name: String

    init(name: String) {
        self.name = name
    }

    func makeSound() {
        print("Some generic sound")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Bark")
    }
}


// Class Conforming to Protocol
// The Circle class conforms to the Drawable protocol, implementing the draw method.
protocol Drawable {
    func draw()
}

class Circle: Drawable {
    var radius: Double

    init(radius: Double) {
        self.radius = radius
    }

    func draw() {
        print("Drawing a circle with radius \(radius)")
    }
}

Putting It All Together

Understanding how TypeScript concepts translate to Swift can make it easier to switch between these languages or even work on projects that require both. By recognizing the parallels and nuances between typeinterface, and class in TypeScript and their Swift equivalents, you can write more robust and maintainable code.

Recap:

  • TypeScript type:
    • Swift equivalent: struct for object types, typealias for type aliases.
  • TypeScript interface:
    • Swift equivalent: protocol.
  • TypeScript class:
    • Swift equivalent: class.

By leveraging these concepts effectively, you can enhance your development skills and become more proficient in both TypeScript and Swift. This knowledge not only broadens your programming capabilities but also prepares you for diverse development challenges.

Conclusion

Mastering both TypeScript and Swift opens up numerous opportunities in the fields of web and mobile development. Understanding the core concepts and their equivalents between these languages is a crucial step in becoming a versatile and effective developer. Whether you’re managing complex types in TypeScript or adhering to strict protocols in Swift, the ability to translate these ideas across languages will significantly enhance your coding prowess.

If you are looking for starting with TypeScript here is a guide on how to set up your first project 🙂