Type narrowing in TypeScript can be tricky, especially when dealing with complex types like `Resu...
Does anyone know how to get type narrowing working on Atom Results? I have an atom that maps 404's to
Option.none()Option.none() and success to Option.some()Option.some() As a result I was wanting NotFoundNotFound to be removed from the return type. I've tried Result.matchResult.match, Result.builderResult.builder and explicit typing but I can't seem to remove it from the typeimport { Atom, Result } from "@effect-atom/atom"
import { Option } from "effect";
// Mock client query that returns Result<Profile, NotFound | ParseError>
type Profile = { user_id: string; name: string };
type ApiError = { _tag: "NotFound" | "ParseError" };
const mockGetUser = Atom.family((id: string) =>
Atom.make((): Result.Result<{ user_id: string; name: string }, { _tag: "NotFound" | "ParseError" }> => {
if (id === 'not-found') {
return Result.fail({ _tag: 'NotFound' as const });
}
if (id === 'parse-error') {
return Result.fail({ _tag: 'ParseError' as const });
}
return Result.success({ user_id: id, name: 'Test User' });
})
);
const userAtomInferred = Atom.make((get) => {
const user_id = 'test_id';
const userResult = get(mockGetUser(user_id)).pipe(
Result.map(Option.some), // Transform Result<UserProfile, E> to Result<Option<UserProfile>, E>
(result) => Result.builder(result)
.onErrorTag('NotFound', () => Result.success(Option.none())) // Handles NotFound
.orElse(() => result) // Leave alone for success, initial, other errors
);
return userResult;
});
// const userResult: Result.Result<Option.Option<{
// user_id: string;
// name: string;
// }>, {
// _tag: "NotFound" | "ParseError"; <--- Would expect "NotFound" to be excluded from type
// }> | Result.Success<Option.Option<never>, never>import { Atom, Result } from "@effect-atom/atom"
import { Option } from "effect";
// Mock client query that returns Result<Profile, NotFound | ParseError>
type Profile = { user_id: string; name: string };
type ApiError = { _tag: "NotFound" | "ParseError" };
const mockGetUser = Atom.family((id: string) =>
Atom.make((): Result.Result<{ user_id: string; name: string }, { _tag: "NotFound" | "ParseError" }> => {
if (id === 'not-found') {
return Result.fail({ _tag: 'NotFound' as const });
}
if (id === 'parse-error') {
return Result.fail({ _tag: 'ParseError' as const });
}
return Result.success({ user_id: id, name: 'Test User' });
})
);
const userAtomInferred = Atom.make((get) => {
const user_id = 'test_id';
const userResult = get(mockGetUser(user_id)).pipe(
Result.map(Option.some), // Transform Result<UserProfile, E> to Result<Option<UserProfile>, E>
(result) => Result.builder(result)
.onErrorTag('NotFound', () => Result.success(Option.none())) // Handles NotFound
.orElse(() => result) // Leave alone for success, initial, other errors
);
return userResult;
});
// const userResult: Result.Result<Option.Option<{
// user_id: string;
// name: string;
// }>, {
// _tag: "NotFound" | "ParseError"; <--- Would expect "NotFound" to be excluded from type
// }> | Result.Success<Option.Option<never>, never>