typed-typings / npm-ramda

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

R.pick requires all of keys #393

Open tomzaku opened 6 years ago

tomzaku commented 6 years ago
import R from 'ramda'

const pickAB = R.pick(['a', 'b'])

pickAB({ a: 1, c: 3 }) 

It has error: "[ts] Argument of type '{ a: number; c: number; }' is not assignable to parameter of type 'Record<"a" | "b", any>'. Object literal may only specify known properties, and 'c' does not exist in type 'Record<"a" | "b", any>'."

But when i write this

import R from 'ramda'

const pickAB = R.pick(['a', 'b'], { a: 1, c: 3 })

The error go away. Did I do something wrong? Thanks for your help

ikatyang commented 6 years ago

Can you share more details (e.g. TS version, tsconfig.json, etc.)? I cannot reproduce the issue.

tomzaku commented 6 years ago

@ikatyang This is my ts info: ts version :

ts-node v6.1.0
node v8.9.4
typescript v2.9.1
 "@types/ramda": "types/npm-ramda#dist",

tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "jsx": "react",
    "noEmit": true,
    "moduleResolution": "node",
    "noImplicitAny": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "baseUrl": ".",
    "paths": {
      "@awesomePath/*": [
        "src/deep/path/*"
      ],
      "@AppFile": ["src/deep/file/index"],
      "@AppTcomb": ["src/mobile/tpl/tcomb/index"]
    },
    "typeRoots": [
      "types"
    ],
    "types": [
      "node"
    ]
  },
  "exclude": [
    "node_modules"
  ]
}
ikatyang commented 6 years ago

The reason why it behaves differently is that we have 3 kind of signature for it:

https://github.com/types/npm-ramda/blob/c813ecac1716f3200b82233d8e87c98db1dd4015/templates/pick.d.ts#L3-L14

TS will try it one by one and pick up the first match as the result. It matches the $record kind in the first example, and the $general kind for the second example.

We can improve it using some conditional types, or as a workaround for now you can manually specify which kind you'd like to use by using selectable overloads:

import R from 'ramda'

const pickAB = R.pick<'1', 'general'>()(['a', 'b'])

pickAB({ a: 1, c: 3 }) 
jcristovao commented 5 years ago

Hey, any news on this topic? If find the proposed solution really bad to read:

const pickAB = R.pick<'1', 'general'>()(['a', 'b'])

It basically implies you need to read the typescript definition, and it's really not clear for the casual code reader.