Start from the beginning: the only expressible constraints for generic types in Swift are protocol conformances, subclassing, and combination of those:
Bool and Bool? are not related in any way by subclassing. The only remaining solution is thus protocol conformance.
So let's define a protocol that only Bool and Bool? conform to!
protocol Boolish { /* any useful common methods here */ }
extension Bool: Boolish { }
extension Optional: Boolish where Wrapped == Bool { }
@propertyWrapper
struct BoolWrapper<Value: Boolish> {
var wrappedValue: Value
}
struct Container {
@BoolWrapper var foo: Bool = true
@BoolWrapper var bar: Bool? = nil
// Error: Referencing initializer 'init(wrappedValue:)' on 'BoolWrapper'
// requires that 'String' conform to 'Boolish'
// @BoolWrapper var baz: String = ""
}
Swift won't let you restrict Boolish conformance on Bool and Bool? only, though. You may have to explicitly document that no other types should adopt this protocol.
For now. My pitch for generalized supertype constraints was well received. We just can't move it forward until somebody volunteers to work on implementation. If / when that happens the compiler would recognize the Bool: Bool? relationship in a generic constraint.
Also for now. Hopefully we can express closed protocols in the language eventually. This has been the topic of several threads in the past.
Yes. The question was framed against the current state of the language, so I did not think it was useful to raise the complexity of the answer, and transform curiosity into mourning of unborn futures. Today I believe my answer is correct, complete, and actionable.