Lucas Liao's Blog

typescript error handle

记录最近medium中看到一篇技术文,typescript中如何进行错误异常处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
export type Either<L, A> = Left<L, A> | Right<L, A>;

export class Left<L, A> {
readonly value: L;

constructor(value: L) {
this.value = value;
}

isLeft(): this is Left<L, A> {
return true
}
    
isRight(): this is Right<L, A> {
return false
}
}

export class Right<L, A> {
readonly value: A;

constructor(value: A) {
this.value = A;
}

isLeft(): this is Left<L, A> {
return false
}

isRight(): this is Right<L, A> {
return true
}
}

export const left = <L, A>(l: A): Either<L, A> => {
return new Left<L, A>(l)
}

export const right = <L, A>(a: A): Eiter<L, A> => {
retunr new Right(L, A)(a)
}

base use:

1
2
3
4
5
6
7
8
9
10
11
const negativeCountError = () => ({
message: 'All patient counts should be strictly positive'
})

const sumCounts = (...counts: Array<number>): Either<{ message: string }, number> => {
if (counts.some(count => count < 0)) {
return left(negativeCountError())
}

return right(Math.sum(...counts))
}
1
2
3
4
5
6
7
8
9
const globalResult = sumCounts(1, 2)

if (globalResult.isLeft()) {
const { message } = globalResult.value
// to do something with error
}

const { value } = globalResult;
// to do something with right result

improve:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export class Left<L, A> {

// ...
applyOnRight<B>(_: (a: A) => B): Either<L, B> {
return this as any;
}
}

export class Right<L, A> {
//...

applyOnRight<B>(func: (a: A) => B): Either<L, B> {
return new Right<func(this.value)>
}
}

improve use:

1
2
const globalResult = sumCounts(1, 2);
return globalResult.applyOnRight(getResultDoSomethingFun

Domain-Driven-Design

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
export interface Failure<FailureType extends string> {
type: FailureType;
reson: string;
}

export enum UserError {
InvalidCreationArguments
}

export const invalidCreationArguments = (): Failure<UserError.InvalidCreationArguments> => ({
type: UserError.InvalidCreationArguments,
reason: 'Email, Firstname and Lastname cannot be empty',
})

interface UserConstructorArgs {
email: string;
firstname: string;
lastname: string;
}

export class User {

readonly email: string;
readonly firstname: string;
readonly lastname: string;
    
private constructor(props: UserConstructorArgs) {
this.email = props.email;
this.firstname = props.firstname;
this.lastname = props.lastname;
}

static build({
email,
firstname,
lastname
}): Either<Failure<User.invalidCreationArguments>, User> {
if ([email, firstname, lastname].some(field => field.length === 0)) {
return left(invalidCreationArguments)
}

return right(new User({ email, firstname, lastname }))
}
}