Error type is not checked
rudolfbyker opened this issue · 3 comments
I would expect this not to compile, because I'm using the wrong error type in functions test1
and test2
:
import { BaseError } from "make-error";
class FooError extends BaseError {}
class BarError extends BaseError {}
function test1(): ResultAsync<string, FooError> {
return errAsync(new BarError("bar"));
}
function test2(): Result<string, FooError> {
return err(new BarError("bar"));
}
However, this seems to go unchecked.
The OK types are checked properly:
function test3(): ResultAsync<string, FooError> {
return okAsync(123); // Type 'number' is not assignable to type 'string'.
}
function test4(): Result<string, FooError> {
return ok(new BarError("bar")); // Type 'number' is not assignable to type 'string'.
}
I wonder if this has to do with the fact that typescript uses structural typing as opposed to nominal typing?
In this case FooError
and BarError
are structurally indistinguishable. If you, say, add distinct attributes to the two types do you get the expected type error?
Interesting, I never thought of that! I will test it ASAP (next week)
This is definitely because of structural vs nominal typing. Here's my recommendation, use symbol
to distinguish between two structurally equivalent types, or some other way to explicitly make the structure distinct.
class BaseError {
readonly prop: string
constructor(val: string) {
this.prop = val
}
}
class FooError extends BaseError {
public is_foo_error: true = true;
}
class BarError extends BaseError {
public is_bar_error: true = true;
}
function test1(): FooError {
return new BarError("bar");
}
You could also use newtype-ts
for nominal typing: https://gcanti.github.io/newtype-ts/