带有 Lodash 的 TypeScript:_.map(["123", " 234 "], _.trim) 返回 boolean[]?

Posted

技术标签:

【中文标题】带有 Lodash 的 TypeScript:_.map(["123", " 234 "], _.trim) 返回 boolean[]?【英文标题】:TypeScript with Lodash: _.map(["123", " 234 "], _.trim) returns boolean[]? 【发布时间】:2017-11-12 01:27:56 【问题描述】:

我有一个字符串数组,它们被分割成这样:

var searchValue = "600-800, 123, 180";
var groups = searchValue.split(","); // => ["600-800", " 123", " 180"]

(因此项目周围可能存在空格),我想删除空格。我知道我可以使用 Array.prototype.mapString.prototype.trim,但我想要一个专门使用 Lodash 的解决方案。

According to the docs,我应该可以说:_.map([' foo ', ' bar '], _.trim);,它会返回['foo', 'bar'],即string[]

但是,TypeScript 对我大吼大叫。这是我在编辑器中看到的内容。

我正在运行 TypeScript 2.3.2 和 Lodash 4.17.4

奇怪的是,如果我说:

var values:string[] = _.map([' foo ', ' bar '], String.prototype.trim);

TypeScript 错误消失了,但是当searchValue 为空并且groups 返回[""] 时出现以下运行时错误:

TypeError: String.prototype.trim 在 null 或 undefined 上调用

我尝试过的事情:

var values:string[] = _.map(_.filter(groups, group => group.indexOf("-") === -1), _.trim);
var values:string[] = _.map(_.filter(groups, function (group)  return group.indexOf("-") === -1; ), _.trim);
var values:string[] = _.map<string, (string?: string, chars?: string) => string>(_.filter(groups, function (group)  return group.indexOf("-") === -1 ), _.trim);
var values:string[] = _.map<string, (string?: string, chars?: string) => string[]>(_.filter(groups, function (group)  return group.indexOf("-") === -1 ), _.trim);
var values:string[] = _.map<string, (string: string, chars: string) => string>(_.filter(groups, function (group)  return group.indexOf("-") === -1 ), _.trim);
var values:string[] = _.map<string, (string: string) => string>(_.filter(groups, function (group)  return group.indexOf("-") === -1 ), _.trim);

一切都无济于事。我很茫然。我在这里做错了什么还是这可能是 Lodash/TypeScript 错误?

【问题讨论】:

【参考方案1】:

以下变体似乎有效:

let values: string[] = _.map(['  foo  ', '  bar  '], str => _.trim(str))

这是我对为什么会发生这种情况的猜测。 map 有很多重载,你想定位这个:

map<T, TResult>(
    collection: List<T> | null | undefined,
    iteratee: ListIterator<T, TResult>
): TResult[];

其中ListIterator 定义为:

type ListIterator<T, TResult> = (value: T, index: number, collection: List<T>) => TResult;

因此,您希望修剪功能与上述ListIterator 的定义相匹配。但是trim实际上定义为:

trim(
    string?: string,
    chars?: string
): string;

所以当你执行以下操作时:

let values: string[] = _.map(['  foo  ', '  bar  '], _.trim);

您实际上最终会遇到不同的过载,其定义为:

    map<T, TObject extends >(
        collection: List<T>|Dictionary<T>|NumericDictionary<T> | null | undefined,
        iteratee?: TObject
    ): boolean[];

所以当你切换到以下变体时:

let values: string[] = _.map(['  foo  ', '  bar  '], str => _.trim(str))

您的修剪函数str =&gt; _trim(str) 符合ListIterator,即使它省略了最后两个参数(indexcollection)。

【讨论】:

很好的解释,这是有道理的。我会在星期一早上首先尝试它,如果它最终对我有用,则标记为已接受。仍然好奇为什么文档会给出他们给出的例子。看起来很奇怪,不是吗? 他们给出的示例使用纯 javascript。但是后来添加了类型定义以在使用 TypeScript 时提供帮助,因此有时您必须更加具体。请注意trim 的第一个参数定义为string,而ListIterator 的第一个参数定义为泛型类型T,在您的情况下是string,因为您有一个string 数组.因此,如果您在纯动态 JavaScript 中运行他们的示例,它会起作用,因为只使用了第一个参数。但是在使用 TypeScript 时必须更加具体,因为它会检查所有参数。【参考方案2】:

问题是_.trim 可以接受两个参数:

trim(string?: string, chars?: string): string;

这与 lodash 的 ListIterator 类型不兼容,其中第二个参数(如果存在)是一个数字(索引)。

因此,编译器正在回退到 _.map 函数的不同类型,这是一个模糊的函数,它将一个对象作为迭代对象并返回一个布尔数组(“对于给定对象的属性的元素返回 true,否则为假。”)

Frank Modica 的回答给出了正确的解决方案。

【讨论】:

感谢您的解释,这很有帮助。让我想知道为什么这些文档会给出他们给出的例子 - 看起来很奇怪,不是吗?

以上是关于带有 Lodash 的 TypeScript:_.map(["123", " 234 "], _.trim) 返回 boolean[]?的主要内容,如果未能解决你的问题,请参考以下文章

typescript 引入 lodash 正确姿势

如何在 TypeScript 中重新导出单个 lodash 模块

[TypeScript] Type Definitions and Modules

[TypeScript] Using Lodash in TypeScript with Typings and SystemJS

如何正确使用带有 lodash debounce 的 Vue JS 手表

Lodash _.debounce 具有用于独特参数变体的单独队列