TsMonad
TsMonad copied to clipboard
Be `strictNullChecks` compatibility
Currently, when using this library with the flag enabled we have the following issue:
const object: { value: number | null } = { value: null };
const result: number | null = Maybe.maybe(object)
.map(obj => obj.value)
.valueOr(10);
As you can see result keeps the type null, since the current typings reflect this. It would be nice if the type for map could reflect the removal of null. Example:
map: <U>(f: (t: T) => U | null) => Maybe<U>;
I saw that in https://github.com/cbowdon/TsMonad/issues/31 this point has been mentioned and fixed for Maybe.maybe but not in general.
Currently there is not a single optional or maybe typescript library out there that is fully strictNullChecks compatible.
My question, is this planned?
Working on an alternative library with pretty similar functionality and modern TS support:
https://github.com/patrickmichalina/typescript-monads
@patrickmichalina yeah, we can all build our own library, just kinda defeats the purpose :)
Hmm, looking at your code, I think it also only handles undefined not null. Also I think it might swallow empty strings, 0, and false and there seems no way to map the wrapped value, as map looks like a flatMap.
If people kept up on their repos, it wouldn’t be necessary :)
I’ll check out your comments and adjust accordingly. Thanks.
@patrickmichalina @JohannesHome Sorry for bothering you with same repeated idea. I recently built https://github.com/Ailrun/typed-f and I believe these packages satisfy all usage with strictNullChecks.
However, this package is still in 0.* version so I need more helps from forks. If you are willing to, please take a look :smile:
@Ailrun looks good, but it it isn't type safe. Simple example is already the signature for Maybe.from(value?: null): Nothing<any>;, it should infer the type base on the input parameter instead of using any.
This let's me do stuff like this:
const test: string | undefined = undefined;
const from = Maybe.from(test);
const result: string = from.valueOr(1);
without a compile error. Also the docs could be more comprehensive.
And yeah I know I can force the type with Maybe<string>, but it's nicer if the monad infers the type 😄 (less work for me)
@JohannesHome Oh, thank you for feedback. However, even with following type,
Maybe.from<T>(value?: null): Nothing<T>;
Following code will give you wrong type.
const test: string | undefined = undefined;
const from = Maybe.from(test); // This will give you Nothing<{}>
Though it will give you an error for following statement.
const result: string = from.valueOr(1); // Complain about that `{}` cannot be assigned to `string`.
@JohannesHome Following code will give you better explanation.
function x(test: string | undefined) {
const from = Maybe.from(test);
return from.valueOr(1); // Give you an error!
}
Your code works since TS think your test as just undefined, and that's why following also works in TS.
const test: string | undefined = undefined;
const x: number | undefined = test;
@Ailrun this is a bit out of scope but your library could infer the type based on the actual value like so Maybe.from<T>(value?: T): Nothing<T> which is the same as Maybe.from<T>(value: T | undefined): Nothing<T>, this allows the compiler to infer the type correctly and making it typesafe without having to specifying the return type (something I like to forget).
@JohannesHome ~It will give you Nothing<undefined>, not Nothing<string>. To be clear, this is because of TS inference, not because of some typing of the library.
See
https://www.typescriptlang.org/play/index.html#src=interface%20Test%3CT%3E%20%7B%0D%0A%20%20v%3A%20T%3B%0D%0A%7D%0D%0Adeclare%20function%20x%3CT%3E(v%3A%20T%20%7C%20undefined)%3A%20Test%3CT%3E%3B%0D%0Aconst%20t%3A%20string%20%7C%20undefined%20%3D%20undefined%3B%0D%0Aconst%20y%20%3D%20x(t)%3B%0D%0Aconst%20test1%3A%20Test%3Cstring%3E%20%3D%20y%3B%0D%0Aconst%20test2%3A%20Test%3Cundefined%3E%20%3D%20y%3B%0D%0A~
@JohannesHome These are all because TS knows what the value of test is in compile time, since you declare const test: string | undefined = undefined. As I said, TS consider this test as undefined, so you can assign this value to any type that accepts undefined. You already loose your string type.
~However, if it's still unclear to you, could you open an issue on my repo? Explaining things related with my code in this repo feels somewhat weird for me :sweat_smile:~ https://github.com/Ailrun/typed-f/issues/46