Skip to content

Commit

Permalink
fix: use generic self-types
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jklmli committed Jul 5, 2017
1 parent bad0f55 commit 1137b8a
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/option/none.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class None_<A> implements Option<A> {
throw new Option.NoSuchElementError();
}

getOrElse<B, A extends B>(this: None_<A>, defaultValue: () => B): B {
getOrElse<B, A extends B>(this: Option<A>, defaultValue: () => B): B {
return defaultValue();
}

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

orElse<B, A extends B>(this: None_<A>, alternative: () => Option<B>): Option<B> {
orElse<B, A extends B>(this: Option<A>, alternative: () => Option<B>): Option<B> {
return alternative();
}
}
Expand Down
12 changes: 8 additions & 4 deletions src/option/some.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class Some<A> implements Option<A> {
return this.value;
}

getOrElse<B, A extends B>(this: Some<A>, defaultValue: () => B): B {
return this.value;
getOrElse<B, A extends B>(this: Option<A>, defaultValue: () => B): B {
const self: Some<A> = this as Some<A>;

return self.value;
}

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

orElse<B, A extends B>(this: Some<A>, alternative: () => Option<B>): Option<B> {
return this;
orElse<B, A extends B>(this: Option<A>, alternative: () => Option<B>): Option<B> {
const self: Some<A> = this as Some<A>;

return self;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/try/failure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Failure<A> implements Try<A> {
throw this.error;
}

getOrElse<B, A extends B>(this: Failure<A>, defaultValue: () => B): B {
getOrElse<B, A extends B>(this: Try<A>, defaultValue: () => B): B {
return defaultValue();
}

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

orElse<B, A extends B>(this: Failure<A>, alternative: () => Try<B>): Try<B> {
orElse<B, A extends B>(this: Try<A>, alternative: () => Try<B>): Try<B> {
return alternative();
}

Expand Down
12 changes: 8 additions & 4 deletions src/try/success.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@ class Success<A> implements Try<A> {
return this.value;
}

getOrElse<B, A extends B>(this: Success<A>, defaultValue: () => B): B {
return this.value;
getOrElse<B, A extends B>(this: Try<A>, defaultValue: () => B): B {
const self: Success<A> = this as Success<A>;

return self.value;
}

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

orElse<B, A extends B>(this: Success<A>, alternative: () => Try<B>): Try<B> {
return this;
orElse<B, A extends B>(this: Try<A>, alternative: () => Try<B>): Try<B> {
const self: Success<A> = this as Success<A>;

return self;
}

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

0 comments on commit 1137b8a

Please sign in to comment.