The title may seem a little confusing, but consider this scenario. We have the following extensions on UIView
for iOS/iPadOS apps.
import UIKit
extension UIView {
var isVisible:Bool{
get{ return !isHidden }
set{ isHidden = !newValue }
}
func addSubviews(_ subviews:UIView...) {
addSubviews(subviews)
}
func addSubviews(_ subviews:[UIView]) {
subviews.forEach{ addSubview($0) }
}
}
We have the exact same extensions on NSView
for macOS apps.
import AppKit
extension NSView {
var isVisible:Bool{
get{ return !isHidden }
set{ isHidden = !newValue }
}
func addSubviews(_ subviews: NSView...) {
addSubviews(subviews)
}
func addSubviews(_ subviews: [NSView]) {
subviews.forEach{ addSubview($0) }
}
}
The only difference between the two is one uses UIView
, the other uses NSView
.
To get rid of that redundancy, and to eliminate having to add the platform checks everywhere, we simply aliased the class names themselves, then built the APIs around those aliases, like so...
#if os(iOS) || os(tvOS)
import UIKit
typealias PlatformView = UIView
#elseif os(OSX)
import AppKit
typealias PlatformView = NSView
#endif
extension PlatformView {
var isVisible:Bool{
get{ return !isHidden }
set{ isHidden = !newValue }
}
func addSubviews(_ subviews: PlatformView...) {
addSubviews(subviews)
}
func addSubviews(_ subviews:[PlatformView]) {
subviews.forEach{ addSubview($0) }
}
The issue is we now have to expose PlatformView
publicly, which may confuse those importing our Swift package. We're hoping they would just see either UIView
or NSView
depending on their platform.
So... is that possible to hide your type aliases and instead expose the public types they alias?
What you expect is the behaviour of preprocecessor macros. Typealiases are replaced to their underlying types at compile time, which makes them identical to the types they alias.
However, the interfaces using a type alias will still expose the type alias instead of the underlying type, since one of the main use cases of type aliases is to provide a more meaningful (at least in some context) name to other types or to combine several types (like typealias ABProtocol = AProtocol & BProtocol
) into a single name, so the interfaces not exposing said type aliases would take away one of the main use cases of typealias
es.
As I've stated in the beginning of my answer, you would to use preprocessor macros to replace your type alias with the represented type before compilation time and hence to expose the aliased type in your public interface.
However, sadly in Swift preprocessor macros aren't as powerful as in Obj-C. You cannot replace type names in preprocessor macros and cannot place type declarations/the opening of an extension in a preprocessor macro.
So there is no way to achieve your goal of avoiding both code duplication and having to expose a type alias in your public interface.