I have the following structure:
type Result<TNotification, TSuccess> = Success<TNotification, TSuccess> | Notifier<TNotification, TSuccess>;
abstract class ResultAbstract<TNotification, TSuccess> {
protected constructor(protected readonly result: TNotification | TSuccess) {}
abstract isSuccess(): this is Success<TNotification, TSuccess>;
abstract isFailure(): this is Notifier<TNotification, TSuccess>;
abstract getData(): TNotification | TSuccess;
}
class Success<F, S> extends ResultAbstract<F, S> {
constructor(readonly data: S) {
super(data);
}
isSuccess(): this is Success<F, S> {
return true;
}
isFailure(): this is Notifier<F, S> {
return false;
}
getData(): S {
return this.result as S;
}
}
class Notifier<E, _> extends ResultAbstract<E, _> {
constructor(readonly data: E) {
super(data);
}
isSuccess(): this is Success<E, _> {
return false;
}
isFailure(): this is Notifier<E, _> {
return true;
}
getData(): E {
return this.result as E;
}
}
class Fail {}
class User {
constructor(private name: string){}
}
I am basically trying to build a notification pattern for handling exceptions on my code flow. I have the following functions:
const findUser = (): Result<Fail, User> => {
if(Math.random() * 0.5 < 0.2)
return new Success(new User('Tony stark'))
return new Notifier(new Error('Usuário não existe'))
}
const userExists = () => {
const result = findUser()
if(result.isFailure()) return 'Not found'
const user = result.getData() // Property 'getData' does not exist on type 'never'.(2339)
return user.name
}
console.log(userExists())
The Result type is a union of either Notifier (For errors) or Success, but if I call one of the type guards on the union it does not narrow the remainder (the "else" statement) to the other half of the union.
If I explicitly call the second type guard, it works as expected:
const userExists = () => {
const result = findUser()
if(!result.isSuccess()) return 'Not found'
const user = result.getData()
return user.name
}
console.log(userExists()) // it works!
The sample code is here in this playground
Can anyone help me understand this?