Just noticed that Swift doesn't narrow types.
For example, variable a is Int?, and getting into the if statement if a is not nil, so I think compiler can assume a is Int, but why I still need to unwrap a inside if statement? I know I can use if let statement, but I'm wondering why Swift doesn't support type narrowing like Typescript.
Any plans to support this or are there any reasons why Swift can't do this?
var a: Int? = 10
if a != nil {
var bar: Int = a // error: Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
}
// of course this works
if let unwrapA = a {
var bar: Int = unwrapA
}
There have been several discussions in the past about this feature:
November 2016:
October 2020:
September 2022:
Notably, in the Nov 2016 thread, Chris Lattner wrote:
There were also questions about how it would interact with overload selection, how it would work with stored class properties (that might get changed while your code is running), and how it would work with computed variables.
Personally, I’ve never really wanted a feature like this. if let works fine for me. I’ve never used a language with this feature before, though, so maybe I just don’t know the benefits.
Type narrowing doesn't work well for mutable stored properties and computed properties. There's no guarantee that it being non-nil at the time of first check will mean it's still nil when called the second time.
Oh, and TypeScript's type narrowing is basically completely wrong when dealing with instance variables:
class Demo {
a: number | undefined
constructor() {
this.a = 123;
}
main() {
if (this.a !== undefined) { // Time of check
this.doSomeArbitraryThing();
const bar: number = this.a; // Time of use
console.log(bar); // undefined!
}
}
// Some arbitrary computation, which can change the state of the world
// Invalidating the "a isn't undefined" conclusion we made in the `if` above.
doSomeArbitraryThing() {
this.a = undefined
}
}
new Demo().main()