ts-results-es
Version:
A TypeScript implementation of Rust's Result and Option objects.
294 lines (247 loc) • 9.76 kB
text/typescript
import { Err, Ok, Result } from '../src/index.js';
import { Observable, of } from 'rxjs';
import {
elseMap,
elseMapTo,
filterResultErr,
filterResultOk,
resultMap,
resultMapErr,
resultMapErrTo,
resultMapTo,
resultMergeMap,
resultSwitchMap,
tapResultErr,
tapResultOk,
} from '../src/rxjs-operators/index.js';
import { eq } from './util.js';
const goodVal: Observable<Result<string, number>> = of(Ok('good'));
const badVal: Observable<Result<string, number>> = of(Err(0));
test('resultMap', () => {
const goodValMapped = goodVal.pipe(
resultMap((msg) => {
eq<typeof msg, string>(true);
return !!msg;
}),
);
eq<typeof goodValMapped, Observable<Result<boolean, number>>>(true);
expect(goodValMapped).toMatchObsResult(Ok(true));
const badValMapped = badVal.pipe(
resultMap((msg) => {
eq<typeof msg, string>(true);
return !!msg;
}),
);
eq<typeof badValMapped, Observable<Result<boolean, number>>>(true);
expect(badValMapped).toMatchObsResult(Err(0));
});
test('resultMapErr', () => {
const goodValMappedErr = goodVal.pipe(
resultMapErr((num) => {
eq<typeof num, number>(true);
return new Date(num);
}),
);
eq<typeof goodValMappedErr, Observable<Result<string, Date>>>(true);
expect(goodValMappedErr).toMatchObsResult(Ok('good'));
const badValMappedErr = badVal.pipe(
resultMapErr((num) => {
eq<typeof num, number>(true);
return new Date(num);
}),
);
eq<typeof badValMappedErr, Observable<Result<string, Date>>>(true);
expect(badValMappedErr).toMatchObsResult(Err(new Date(0)));
});
test('resultMapTo', () => {
const goodValMappedTo = goodVal.pipe(resultMapTo(500));
eq<typeof goodValMappedTo, Observable<Result<number, number>>>(true);
expect(goodValMappedTo).toMatchObsResult(Ok(500));
const badValMappedTo = badVal.pipe(resultMapTo(500));
eq<typeof badValMappedTo, Observable<Result<number, number>>>(true);
expect(badValMappedTo).toMatchObsResult(Err(0));
});
test('resultMapErrTo', () => {
const goodValMappedErrTo = goodVal.pipe(resultMapErrTo('err'));
eq<typeof goodValMappedErrTo, Observable<Result<string, string>>>(true);
expect(goodValMappedErrTo).toMatchObsResult(Ok('good'));
const badValMappedErrTo = badVal.pipe(resultMapErrTo('err'));
eq<typeof badValMappedErrTo, Observable<Result<string, string>>>(true);
expect(badValMappedErrTo).toMatchObsResult(Err('err'));
});
test('elseMap', () => {
const goodValElseMapped = goodVal.pipe(
elseMap((num) => {
eq<typeof num, number>(true);
return new Date(num);
}),
);
eq<typeof goodValElseMapped, Observable<string | Date>>(true);
expect(goodValElseMapped).toMatchObs('good');
const badValElseMapped = badVal.pipe(
elseMap((num) => {
eq<typeof num, number>(true);
return new Date(num);
}),
);
eq<typeof badValElseMapped, Observable<string | Date>>(true);
expect(badValElseMapped).toMatchObs(new Date(0));
});
test('elseMapTo', () => {
const goodValElseMapped = goodVal.pipe(elseMapTo(new Date(100)));
eq<typeof goodValElseMapped, Observable<string | Date>>(true);
expect(goodValElseMapped).toMatchObs('good');
const badValElseMapped = badVal.pipe(elseMapTo(new Date(100)));
eq<typeof badValElseMapped, Observable<string | Date>>(true);
expect(badValElseMapped).toMatchObs(new Date(100));
});
test('switchMap', async () => {
const goodValSwitchMappedToResult = goodVal.pipe(
resultSwitchMap((a) => {
eq<typeof a, string>(true);
return of(Ok(new Date(3)) as Result<Date, string>);
}),
);
eq<typeof goodValSwitchMappedToResult, Observable<Result<Date, number | string>>>(true);
expect(goodValSwitchMappedToResult).toMatchObsResult(Ok(new Date(3)));
const goodValSwitchMappedToBadResult = goodVal.pipe(
resultSwitchMap((a) => {
eq<typeof a, string>(true);
return of(Err(new Date(3)) as Result<number, Date>);
}),
);
eq<typeof goodValSwitchMappedToBadResult, Observable<Result<number, Date | number>>>(true);
expect(goodValSwitchMappedToBadResult).toMatchObsResult(Err(new Date(3)));
const badValSwitchMappedToResult = badVal.pipe(
resultSwitchMap((a) => {
eq<typeof a, string>(true);
return of(Ok(new Date(3)) as Result<Date, string>);
}),
);
eq<typeof badValSwitchMappedToResult, Observable<Result<Date, number | string>>>(true);
expect(badValSwitchMappedToResult).toMatchObsResult(Err(0));
const goodValSwitchMappedToNonResult = goodVal.pipe(
resultSwitchMap((a) => {
eq<typeof a, string>(true);
return of(new Date(3));
}),
);
eq<typeof goodValSwitchMappedToNonResult, Observable<Result<Date, number>>>(true);
expect(goodValSwitchMappedToNonResult).toMatchObsResult(Ok(new Date(3)));
const badValSwitchMappedToNonResult = badVal.pipe(
resultSwitchMap((a) => {
eq<typeof a, string>(true);
return of(new Date(3));
}),
);
eq<typeof badValSwitchMappedToNonResult, Observable<Result<Date, number>>>(true);
expect(badValSwitchMappedToNonResult).toMatchObsResult(Err(0));
});
test('switchMap', async () => {
const goodValMergeMappedToResult = goodVal.pipe(
resultMergeMap((a) => {
eq<typeof a, string>(true);
return of(Ok(new Date(3)) as Result<Date, string>);
}),
);
eq<typeof goodValMergeMappedToResult, Observable<Result<Date, number | string>>>(true);
expect(goodValMergeMappedToResult).toMatchObsResult(Ok(new Date(3)));
const goodValMergeMappedToBadResult = goodVal.pipe(
resultMergeMap((a) => {
eq<typeof a, string>(true);
return of(Err(new Date(3)) as Result<number, Date>);
}),
);
eq<typeof goodValMergeMappedToBadResult, Observable<Result<number, Date | number>>>(true);
expect(goodValMergeMappedToBadResult).toMatchObsResult(Err(new Date(3)));
const badValMergeMappedToResult = badVal.pipe(
resultMergeMap((a) => {
eq<typeof a, string>(true);
return of(Ok(new Date(3)) as Result<Date, string>);
}),
);
eq<typeof badValMergeMappedToResult, Observable<Result<Date, number | string>>>(true);
expect(badValMergeMappedToResult).toMatchObsResult(Err(0));
const goodValMergeMappedToNonResult = goodVal.pipe(
resultMergeMap((a) => {
eq<typeof a, string>(true);
return of(new Date(3));
}),
);
eq<typeof goodValMergeMappedToNonResult, Observable<Result<Date, number>>>(true);
expect(goodValMergeMappedToNonResult).toMatchObsResult(Ok(new Date(3)));
const badValMergeMappedToNonResult = badVal.pipe(
resultMergeMap((a) => {
eq<typeof a, string>(true);
return of(new Date(3));
}),
);
eq<typeof badValMergeMappedToNonResult, Observable<Result<Date, number>>>(true);
expect(badValMergeMappedToNonResult).toMatchObsResult(Err(0));
});
test('filterResultOk', () => {
const filteredGoodVal = goodVal.pipe(filterResultOk());
eq<typeof filteredGoodVal, Observable<string>>(true);
expect(filteredGoodVal).toMatchObs('good');
let hitBadVal = false;
const filteredBadVal = badVal.pipe(filterResultOk());
eq<typeof filteredBadVal, Observable<string>>(true);
filteredBadVal.subscribe(() => (hitBadVal = false));
expect(hitBadVal).toEqual(false);
});
test('filterResultErr', () => {
let hitGoodVal = false;
const filteredGoodVal = goodVal.pipe(filterResultErr());
eq<typeof filteredGoodVal, Observable<number>>(true);
filteredGoodVal.subscribe(() => (hitGoodVal = false));
expect(hitGoodVal).toEqual(false);
const filteredBadVal = badVal.pipe(filterResultErr());
eq<typeof filteredBadVal, Observable<number>>(true);
expect(filteredBadVal).toMatchObs(0);
});
test('tapResultOk', () => {
let hitGoodVal = false;
const tappedGoodVal = goodVal.pipe(
tapResultOk((val) => {
eq<typeof val, string>(true);
expect(val).toEqual('good');
hitGoodVal = true;
}),
);
eq<typeof tappedGoodVal, Observable<Result<string, number>>>(true);
expect(tappedGoodVal).toMatchObsResult(Ok('good'));
expect(hitGoodVal).toEqual(true);
let hitBadVal = false;
const tappedBadVal = badVal.pipe(
tapResultOk((val) => {
eq<typeof val, string>(true);
hitBadVal = true;
}),
);
eq<typeof tappedBadVal, Observable<Result<string, number>>>(true);
expect(tappedBadVal).toMatchObsResult(Err(0));
expect(hitBadVal).toEqual(false);
});
test('tapResultErr', () => {
let hitGoodVal = false;
const tappedGoodVal = goodVal.pipe(
tapResultErr((val) => {
eq<typeof val, number>(true);
hitGoodVal = true;
}),
);
eq<typeof tappedGoodVal, Observable<Result<string, number>>>(true);
expect(tappedGoodVal).toMatchObsResult(Ok('good'));
expect(hitGoodVal).toEqual(false);
let hitBadVal = false;
const tappedBadVal = badVal.pipe(
tapResultErr((val) => {
eq<typeof val, number>(true);
expect(val).toEqual(0);
hitBadVal = true;
}),
);
eq<typeof tappedBadVal, Observable<Result<string, number>>>(true);
expect(tappedBadVal).toMatchObsResult(Err(0));
expect(hitBadVal).toEqual(true);
});