typed-typings / npm-ramda

TypeScript's type definitions for Ramda
MIT License
384 stars 64 forks source link

How to type pathOr? #445

Open codingedgar opened 4 years ago

codingedgar commented 4 years ago

This lib has improved a lot! and keep me from abandoning Ramda so Thanks to all 👏 💛

I don't get much how to type pathOr:

ttype Obj = {
  selected: boolean
} | undefined

const obj: Obj = undefined
const obj1: {} = {}
const obj2: Obj = { selected: true }

const selected: boolean = pathOr(true, ['selected'], obj || {}); // => Argument of type 'undefined' is not assignable to parameter of type '{}'.
const selected1: boolean = pathOr(true, ['selected'], obj1); // => this is unknown not boolean
const selected2: boolean = pathOr(true, ['selected'], obj2); // => this is unknown not boolean

const selected3: boolean = pathOr<boolean>(true, ['selected'], obj2); // => Argument of type 'string[]' is not assignable to parameter of type 'Placeholder'.
const selected4: boolean = pathOr<boolean, boolean>(true, ['selected'], obj2); // => this actually outputs boolean
//                                         ^ this works?(the second boolean, doesn't make much sense to me)
const selected5: boolean = pathOr(true)(['selected'])(obj2); // => this is unknown not boolean
const selected6: boolean = pathOr<boolean>(true)(['selected'])(obj2); // => this is unknown not boolean
const selected7: boolean = pathOr<boolean, any>(true)(['selected'])(obj2); // => Expected 3 arguments, but got 1.
const selected8: boolean = pathOr<boolean, boolean>(true)(['selected'])(obj2); // => Expected 3 arguments, but got 1.
const selected9: boolean = pathOr<boolean, boolean, Obj>(true, ['selected'], obj2); // => Expected 2 type arguments, but got 3.
const selected10: boolean = pathOr<boolean, Obj>(true, ['selected'], obj2); // => Type 'pathOr_111<boolean, Obj>' is not assignable to type 'boolean'.

Oversimplifying a lot, I would expect it to behave is something more like:

type pathOr = <T, U>(defaults: T, path: string[], obj: any) => T | U
type pathOr = <T, U>(defaults: T) => (path: string[]) => (obj: any) => T | U

It returns the same type as the defaults or the supposed type. I know this is not as simple to make, it's just a how I would expect it to behave when actually working with pathOr

So my question actually is: What's the best way to type/use pathOr ?