如何将 R.pick 与 TypeScript 一起使用
Posted
技术标签:
【中文标题】如何将 R.pick 与 TypeScript 一起使用【英文标题】:How to use R.pick with TypeScript 【发布时间】:2020-04-16 08:49:08 【问题描述】:我正在尝试类似的东西
import R from 'ramda'
import fs from 'fs'
import path from 'path'
import promisify from 'util'
const readFile = promisify(fs.readFile)
export async function discoverPackageInfo(): Promise<
name: string,
version: string
description: string
>
return readFile(path.join(__dirname, '..', 'package.json'))
.then(b => b.toString())
.then(JSON.parse)
.then(R.pick([
'name',
'description',
'version',
]))
但我得到了
src/file.ts:13:3 - error TS2322: Type ' name: string; version: string; description: string; | Pick<any, never>' is not assignable to type ' name: string; version: string; description: string; '.
Type 'Pick<any, never>' is missing the following properties from type ' name: string; version: string; description: string; ': name, version, description
13 return readFile(path.join(__dirname, '..', 'package.json'))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14 .then(b => b.toString())
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
19 'version',
~~~~~~~~~~~~~~~~
20 ]))
~~~~~~~
我做错了什么?
【问题讨论】:
是的,我知道使用async
和.then
不太合乎情理。
async
在这里实际上是不必要的。没有它,代码也可以工作
正确。但是,我正在构建我的代码以在非 CPU 的任何东西上进行异步,以便强制正确地思考问题。最终成为结构和注释方面的练习,我发现它对我有很大帮助。
【参考方案1】:
JSON.parse
returns any
。 R.pick
之后的返回类型解析如下:
.then(R.pick([ 'name', 'description', 'version' ]))
=>
type Return = Pick<any, Inner> // resolves to ; any stems from JSON.parse
type Inner = Exclude<keyof any,
Exclude<keyof any, "name" | "description" | "version">> // never
你想要 name: string, version: string description: string
,但得到。为了解决这个问题,assert the desired type 显式为
JSON.parse
(我将其命名为MyThing
):
readFile(path.join(__dirname, "..", "package.json"))
.then(b => b.toString())
.then(s => JSON.parse(s) as MyThing)
.then(R.pick(["name", "description", "version"]));
Parsing can be made more type-safe,例如通过使用assertion functions / 类型守卫:
export async function discoverPackageInfo(): Promise<MyThing>
return readFile(...).then(...)
.then(safeParse(assertMyThing)) // <-- change
.then(R.pick(...));
const safeParse = <T>(assertFn: (o: any) => asserts o is T) => (s: string) =>
const parsed = JSON.parse(s);
assertFn(parsed);
return parsed;
function assertMyThing(o: any): asserts o is MyThing
if (!("name" in o) || !("version" in o) || !("description" in o))
throw Error();
Playground (playground 中的外部类型导入可能需要一些时间来加载,否则粘贴到您自己的环境中)
【讨论】:
帮了大忙,谢谢!有没有更标准/打包的方式来做到这一点?比如,从类型定义生成一个断言函数?我没有读过手册(我只是通过练习来学习),我会很感激任何指点! 我不确定断言函数的生成器。但是那里有很多自动生成的类型保护库,我个人觉得io-ts 和typescript-is 很有吸引力!并且似乎得到了积极的维护和支持。您也可以查看 these posts 作为起点。 顺便说一句:如果你想使用基于生成的类型保护的断言函数,转换应该没问题,比如this。 作为参考,我最终得到了这个:gist.github.com/pkoch/9062725ef441d80649f00964f9f424b7以上是关于如何将 R.pick 与 TypeScript 一起使用的主要内容,如果未能解决你的问题,请参考以下文章
Angularjs + Typescript,如何将 $routeParams 与 IRouteParamsService 一起使用
将 Typescript 与 Jest 一起使用时如何测试超级调用?
如何将 Angular $http 与 typescript 泛型一起使用
如何将 TypeScript 与 withRouter、connect、React.Component 和自定义属性一起使用?