1. Introduction
Swift currently provides several access modifiers (private, fileprivate, internal, public, open), but no modifier allows restricting visibility to a type and its extensions across files.
This proposal introduces a new access level:
typeprivate
typeprivate allows symbols to be accessed only by the declaring type (class / struct / enum) and its extensions, regardless of file boundaries. This access level provides finer encapsulation without forcing code organization into a single file.
2. Motivation
Swift uses private to restrict visibility to a declaration scope, but this is file-scoped, not type-scoped:
| Modifier | Same Type | Same File Extension | Other File Extension | Other Types |
|---|---|---|---|---|
private |
✓ (same file) | ✓ | ✗ | ✗ |
fileprivate |
✓ | ✓ | ✗ | ✓ (same file) |
internal |
✓ | ✓ | ✓ | ✓ |
| (missing) | type | type | type | ✗ |
Problems commonly encountered:
2.1 Large types split into multiple files
Developers often split a large type into multiple files using extensions:
-
To separate protocol conformances
-
To organize functionality
-
For readability and maintainability
However, because private cannot be accessed in extensions in different files, developers are forced to:
-
Make a member
fileprivate(too broad) -
Make it
internal(way too broad) -
Merge files (hurts maintainability)
2.2 Current workarounds are inadequate
Problem with fileprivate
fileprivate gives access to other unrelated types within the same file:
fileprivate var cache: [String: User] = [:] // too visible
Problem with internal
internal allows access from entire module, exposing implementation details.
2.3 Developers want “type-only encapsulation”
There is no way to get:
private to the type, not the file.
This capability exists in languages like Kotlin (private constructor() + multi-file class) and C# (private + partial classes).
Swift's extensions are commonly used to break a type across files — but the language does not support a type-based access level.
3. Proposed Solution
Introduce a new access modifier:
typeprivate
Meaning:
A declaration is visible only within the same type (class, struct, enum) and any of its extensions, regardless of file boundaries.
3.1 Example
// File A
struct UserManager {
typeprivate var cache: [String: User] = [:]
}
// File B
extension UserManager {
func reset() {
cache.removeAll() // allowed
}
}
// File C
struct Logger {
func test() {
let u = UserManager()
u.cache // error: 'cache' is typeprivate
}
}