Branching `if` statement in `Either.chainW` doesn't union properly
See original GitHub issueš Bug report
Current Behavior
Note: example has been replaced with a more representative case
type StoreError = {
type: 'storeError';
excuse: string;
};
type Hotdog = {
type: 'hotdog';
length: 'small' | 'medium' | 'large';
name: string;
};
const getHotdog = (length: Hotdog['length']): E.Either<StoreError, Hotdog> => {
return E.of({
type: 'hotdog',
length,
name: 'Cindy',
})
}
type Sausage = {
type: 'sausage';
length: 'small' | 'medium' | 'large';
name: string;
};
const getSausage = (length: Sausage['length']): E.Either<StoreError, Sausage> => {
return E.of({
type: 'sausage',
length,
name: 'Addison',
})
}
function getMediumHotdogOrSausage(type: 'hotdog' | 'sausage') {
return pipe(
E.of(type),
E.chainW((type) => {
// TS2345: Argument of type '(type: "hotdog" | "sausage") => Left<StoreError> | Right<Hotdog> | Right<Sausage>' is not assignable to parameter of type '(a: "hotdog" | "sausage") => Either<StoreError, Hotdog>'.
// Type 'Left<StoreError> | Right<Hotdog> | Right<Sausage>' is not assignable to type 'Either<StoreError, Hotdog>'.
// Type 'Right<Sausage>' is not assignable to type 'Either<StoreError, Hotdog>'.
// Type 'Right<Sausage>' is not assignable to type 'Right<Hotdog>'.
// Type 'Sausage' is not assignable to type 'Hotdog'.
// Types of property 'type' are incompatible.
// Type '"sausage"' is not assignable to type '"hotdog"'.
if (type === 'hotdog') {
return getHotdog('medium');
}
return getSausage('small');
}),
);
}
Expected behavior
I would expect this to pass type-check and result in a type E.Either<StoreError, Sausage | Hotdog>
.
Is there a better way to represent a branch like this?
Your environment
Which versions of fp-ts are affected by this issue? Did this work in previous versions of fp-ts?
Software | Version(s) |
---|---|
fp-ts | 2.11.8 |
TypeScript | 4.5.5 |
Issue Analytics
- State:
- Created a year ago
- Comments:5
Top Results From Across the Web
Optional chaining does not narrow types in the `else` branch
Successfully merging a pull request may close this issue. Fix discriminant property narrowing through optional chain with null andrewbranch/Ā ...
Read more >All branches in a conditional structure should not have exactly ...
Having all branches in a switch or if chain with the same implementation is an error. Either a copy-paste error was made and...
Read more >Conditional type is not being narrowed by if/else branch
I tried inferring the type using typeof which narrows correctly for new declarations in the branch but does not narrow the callback.
Read more >Documentation - Narrowing - TypeScript
In JavaScript, we can use any expression in conditionals, && s, || s, if statements, Boolean negations ( ! ), and more. As...
Read more >Conditional Branch - an overview | ScienceDirect Topics
Boolean-valued comparisons do not help with the code in Figure 7.9a. The code is equivalent to the straight condition-code scheme. It requires comparisons,Ā ......
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Thanks for the better example.
This is not a
fp-ts
related problem. You can get the same error when exchangingEither
for example withArray
which maybe makes the problem more obvious.The problem is simply that the first return type TypeScript sees is a
string[]
but you want to assign anumber[]
in the second one which typescript interprets in an error on your side. You can work around this error by providing a return type so typescript knows that you want to actually return a combined array type. In this case you can write(string | number)[]
.So in your case you need to provide the return type
E.Either<StoreError, Sausage | Hotdog>
to your arrow function so typescript knows that it should combineSausage
andHotdog
and not treat everyEither
on its own.Thanks for the explanation! So when you say āitās not an
fp-ts
-related problemā do you mean itās inherent to the type system in some way? Because typescript doesnāt seem to have a problem doingif
statement normally. This works fine:Underlying explanation aside, my solution to this problem was to write a custom combinator:
This fulfills our specific use case of āI want to follow a different path of logic depending on a conditionā and āI want to infer the return type so I donāt have to explicitly declare all errors and dependenciesā