logo
© 2025 devxdev. All rights reserved.
AboutGitHub

[Swift] Swift의 protocol keyword와 typescript의 interface 비교

수정일: 2026. 2. 11.

태그:

swift의 protocol keyword

아래와 같이 사용할 수 있습니다.

// swift
protocol Describable {
  var description: String { get };
  func describe()
}

struct Product: Describable {
  var description = "상품"
  func describe() { print(description) }
}

typescript의 interface와 유사합니다.

typescript에선 interface를 implements로 해당 클래스의 shape를 고정해줄 수 있습니다. 하지만 그것 이외의 기능은 추가로 없습니다. (javascript에 타입 도움을 주는 것이 전부이기 때문이죠)

swift에선 struct로 protocol의 shape을 정해줬는데요, 얼핏 봐서는 비슷하지만 다른 점들이 존재합니다.

protocol의 용도

protocol은 어떤 객체의 타입을 지정하는데 사용됩니다. 위에서 예시로 만든 Describable은 Product의 형태를 강제하는데 사용되었습니다.

protocol의 쓸모

protocol만으로도 충분히 강력한 제약을 줄 수 있습니다. 제약은 규칙이 되고 규칙은 안전한 객체 생성을 도와 줄 수 있습니다.

protocol의 get, set 요구사항 명시

// swift
protocol Cat {
  var name: String { get } // 읽기 전용이므로 구현시 let, var를 사용
  var age: Int { get set } // 읽기, 쓰기 모두 구현해야하므로 var를 사용
}

struct Kitty: Cat {
  let name = "kitty"
  var age = 1
}

associatedtype

associatedtype은 typescript의 generic 타입을 생각하면 이해가 편합니다. 호출자가 정해주기까지 타입을 비워둔 상태로 protocol을 생성하는 것입니다.

예를 들어 아래 코드와 같이 Box는 Item이 어떤게 들어올지 모르는 상태로 구조만 잡습니다.

“Item이 뭐가 올지는 모르겠지만 value라는 값은 get, set이 되어야 하고, get으로 Item을 반환 받아야만 해” 를 지정해두는 것입니다.

protocol Box {
  associatedtype Item 
  var value: Item { get set }
  func get() -> Item
}

struct StringBox: Box {
  typealias Item = String
  var value: String = ""
  func get() -> String { return value }
}

protocol이 protocol을 채택하는 것

당연하게도 protocol은 protocol을 채택받을 수 있습니다. 모든 채택을 받은 구현체는 제약에 따라 구현되어야 합니다.

protocol Animal {
  var name: String { get }
}

protocol Pet: Animal {
  var owner: String { get }
}

struct Poppy: Pet {
  let name = "" // Animal의 채택
  let owner =  "" // Pet의 채택
}

// 아래는 다중 채택의 예시입니다.

protocol Bark {
  var sound: String { get }
}

struct Choco: Animal, Bark {
  let name = ""
  let sound = "wangwang"
}

mutating func

mutating func는 protocol 내부에 선언한 property의 값을 변경하겠다는 선언입니다. 위에서 언급한 set도 변경 가능성을 열어둔 선언이였습니다.

set과 다른 점은 protocol을 구현한 구현체 메서드에서 self로 자기 자신에 접근하여 변경하는 경우를 따로 다룬다는 점입니다.

즉 자기 자신에 대한 변경 메서드를 위한 키워드입니다.

swift는 기본적으로 struct에서 자기 자신의 값 변경을 금지합니다.


protocol Counter {
  var count: Int { get set }
  func inc() 
}

struct Counter {
  var count = 0
  func inc () { self.count += 1 } // Left side of mutating operator isn't mutable: 'self' is immutable
}

에러를 읽어보면 self는 immutable하기 때문에 변경하지 말라는 말입니다. js에서도 값 변경을 막기 위해 객체의 write에 frozen을 걸어두는 것과 비슷합니다. 하지만 기본적으로 이미 걸려있다는 점이 다르네요

객체가 생성되면 그 객체의 자기 자신을 가리키는 self는 let으로 생성되기 때문에 이미 상수임을 못박아 둔 상태로 태어납니다.

  • 여기서 struct에 대한 예시만 들고 있습니다. struct는 값 타입이고 class는 참조 타입이기 때문에 따로 다룹니다.

그럼 immutable한 객체를 어떻게 mutating을 붙인다고 해서 값 변경이 가능하게 바꾼다는 걸까요?

답은 바로, mutating을 붙인 func는 해당 스코프 안에서만 self를 let에서 var로 바꿉니다.

struct Counter {
  var count = 0
  mutating func inc() { self.count += 1 } // 여기서 self를 mutable하게 풀어줍니다. 
 //  위의 코드는 이것과 같습니다. self = Counter(count: count + 1)
}

Swift의 프로토콜에 대해 알아봤습니다.

알아보면서 알게된 모든 내용을 정리하려면 끝이 나지 않을 것 같아 protocol에 관한 내용들 중 기존의 멀티 페러다임 언어를 다뤄보신 분들이라면 스킵해도 될법한 내용들은 빼고 swift의 특징적인 점이 묻어나오는 부분들만 정리를 해봤습니다.

static이나 initialize 혹은 class에게만 채택을 열어두는 AnyObject는 swift의 독특한 문법 같아 따로 다루는게 재밌을 것 같습니다.