Skip to content

Commit ec6df9c

Browse files
committed
fix: use generic self-types
getOrElse and orElse use self-types in order to support typed upper bounds.[0] In TypeScript 2.4, generic functions were checked more strictly[1]. This causes the implicit downward type cast to fail, so we explicitly invoke the cast in the method body. This workaround is backwards-compatible with TypeScript 2.3. Bounded polymorphism has been implemented[2], but true F-bounded polymorphism hasn't been. This means a type like interface Option<A, B = Option<A, B>> is invalid. Alternatively, we can solve this with a lower type bound, but these don't work against concrete classes[3]. --- We should also upgrade monapt's TypeScript dependency to 2.4, but there are unrelated errors compiling the tests. [0] microsoft/TypeScript#13337 [1] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#stricter-checking-for-generic-functions [2] https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#type-parameters-as-constraints [3] microsoft/TypeScript#14520
1 parent 77ef7f1 commit ec6df9c

File tree

4 files changed

+20
-12
lines changed

4 files changed

+20
-12
lines changed

src/option/none.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class None_<A> implements Option<A> {
4747
throw new Option.NoSuchElementError();
4848
}
4949

50-
getOrElse<B, A extends B>(this: None_<A>, defaultValue: () => B): B {
50+
getOrElse<B, A extends B>(this: Option<A>, defaultValue: () => B): B {
5151
return defaultValue();
5252
}
5353

@@ -59,7 +59,7 @@ class None_<A> implements Option<A> {
5959
return matcher.None();
6060
}
6161

62-
orElse<B, A extends B>(this: None_<A>, alternative: () => Option<B>): Option<B> {
62+
orElse<B, A extends B>(this: Option<A>, alternative: () => Option<B>): Option<B> {
6363
return alternative();
6464
}
6565
}

src/option/some.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ class Some<A> implements Option<A> {
5353
return this.value;
5454
}
5555

56-
getOrElse<B, A extends B>(this: Some<A>, defaultValue: () => B): B {
57-
return this.value;
56+
getOrElse<B, A extends B>(this: Option<A>, defaultValue: () => B): B {
57+
const self: Some<A> = this as Some<A>;
58+
59+
return self.value;
5860
}
5961

6062
map<B>(mapper: (value: A) => B): Option<B> {
@@ -65,8 +67,10 @@ class Some<A> implements Option<A> {
6567
return matcher.Some(this.value);
6668
}
6769

68-
orElse<B, A extends B>(this: Some<A>, alternative: () => Option<B>): Option<B> {
69-
return this;
70+
orElse<B, A extends B>(this: Option<A>, alternative: () => Option<B>): Option<B> {
71+
const self: Some<A> = this as Some<A>;
72+
73+
return self;
7074
}
7175
}
7276

src/try/failure.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class Failure<A> implements Try<A> {
4545
throw this.error;
4646
}
4747

48-
getOrElse<B, A extends B>(this: Failure<A>, defaultValue: () => B): B {
48+
getOrElse<B, A extends B>(this: Try<A>, defaultValue: () => B): B {
4949
return defaultValue();
5050
}
5151

@@ -57,7 +57,7 @@ class Failure<A> implements Try<A> {
5757
return matcher.Failure(this.error);
5858
}
5959

60-
orElse<B, A extends B>(this: Failure<A>, alternative: () => Try<B>): Try<B> {
60+
orElse<B, A extends B>(this: Try<A>, alternative: () => Try<B>): Try<B> {
6161
return alternative();
6262
}
6363

src/try/success.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ class Success<A> implements Try<A> {
4646
return this.value;
4747
}
4848

49-
getOrElse<B, A extends B>(this: Success<A>, defaultValue: () => B): B {
50-
return this.value;
49+
getOrElse<B, A extends B>(this: Try<A>, defaultValue: () => B): B {
50+
const self: Success<A> = this as Success<A>;
51+
52+
return self.value;
5153
}
5254

5355
map<B>(f: (value: A) => B): Try<B> {
@@ -58,8 +60,10 @@ class Success<A> implements Try<A> {
5860
return matcher.Success(this.value);
5961
}
6062

61-
orElse<B, A extends B>(this: Success<A>, alternative: () => Try<B>): Try<B> {
62-
return this;
63+
orElse<B, A extends B>(this: Try<A>, alternative: () => Try<B>): Try<B> {
64+
const self: Success<A> = this as Success<A>;
65+
66+
return self;
6367
}
6468

6569
recover(fn: (error: Error) => A): Try<A> {

0 commit comments

Comments
 (0)