Lodash\u forEach在TypeScript中破坏typeguard 出身背景

Lodash\u forEach在TypeScript中破坏typeguard 出身背景,typescript,lodash,typescript2.0,union-types,Typescript,Lodash,Typescript2.0,Union Types,当我没有数据时,创建一个变量通知我希望为false,否则创建一个对象数组。所以我做了一个联合类型:let通知:object[]| boolean=[];很好,除非我做通知。推送通知;我得到 对,TS不确定它是否是数组。我会让它知道的。通知=[];同样的错误。再挖一堆,意识到守卫工作得很好,只有当我把我的.推到lodash's forEach里面时,我才得到错误 当前状态: let notifications: object[] | boolean; if (noNotifications) {

当我没有数据时,创建一个变量通知我希望为false,否则创建一个对象数组。所以我做了一个联合类型:let通知:object[]| boolean=[];很好,除非我做通知。推送通知;我得到

对,TS不确定它是否是数组。我会让它知道的。通知=[];同样的错误。再挖一堆,意识到守卫工作得很好,只有当我把我的.推到lodash's forEach里面时,我才得到错误

当前状态:

let notifications: object[] | boolean;

if (noNotifications) {
  notifications = false;
} else {
  notifications = [];
  _forEach(notificationsObj, function (notification, type) { // Culprit
    notification['type'] = type;
    notifications.push(notification); // <-- TS error on push
  });
}
return notifications;
我试过的 一系列不同的类型防护方式。不明白forEach破坏它的原因,所以不确定下一步要尝试什么

问题
是否可以在_forEach内对我的变量使用push?如果是这样的话,怎么做?

TypeScript对通知的理解还不够透彻,以至于在运行回调中的代码之前不会重新分配通知。由于通知不是常量,TypeScript认为可以重新分配通知。TypeScript是如何进行基于类型的控制流分析的,这方面有很多问题;类型收缩传播到闭包是很困难的。由于您无法真正让TypeScript遵循控制流,因此有几个选项:

最简单的方法是在执行推送时仅断言通知是一个数组:

这个断言是告诉编译器不要担心

要以牺牲少量运行时分配混乱为代价获得更高的类型安全性,请引入const变量,然后将其分配给通知:

在这里,TypeScript知道notificationsArray永远不会被重新分配,因此它的类型在回调中一直保持狭窄的object[]。然后可以将其值分配给通知。您也可以将notificationsArray声明为object[]类型,而不使用| boolean。我只是想说明常数对变窄的影响


希望您理解,并且其中一个解决方案适合您。祝你好运

TypeScript不太了解_forEach,不知道在运行回调中的代码之前不会重新分配通知。由于通知不是常量,TypeScript认为可以重新分配通知。TypeScript是如何进行基于类型的控制流分析的,这方面有很多问题;类型收缩传播到闭包是很困难的。由于您无法真正让TypeScript遵循控制流,因此有几个选项:

最简单的方法是在执行推送时仅断言通知是一个数组:

这个断言是告诉编译器不要担心

要以牺牲少量运行时分配混乱为代价获得更高的类型安全性,请引入const变量,然后将其分配给通知:

在这里,TypeScript知道notificationsArray永远不会被重新分配,因此它的类型在回调中一直保持狭窄的object[]。然后可以将其值分配给通知。您也可以将notificationsArray声明为object[]类型,而不使用| boolean。我只是想说明常数对变窄的影响


希望您理解,并且其中一个解决方案适合您。祝你好运

jcalz的回答解决了您的具体问题,但我只是想提供一种不同的方法来解决您的问题。通过以功能性风格编写,您可以完全避免这些问题

import * as _ from 'lodash';

function getNotifications(notificationsObj: {[type: string]: object}): object[] | boolean {
  if (_.isEmpty(notificationsObj)) {
    return false;
  } else {
    // note: lodash map will turn an object into an array
    return _.map(notificationsObj, (notification, type) => {
      return {...notification, type};
    });
  }
}

注意:与原始解决方案相比,我还避免了对原始通知对象进行变异。如果你依赖于正在发生的突变,那么你应该将该部分改变回去。

jcalz的答案解决了你的具体问题,但我只是想提供一种不同的方法来解决你的问题。通过以功能性风格编写,您可以完全避免这些问题

import * as _ from 'lodash';

function getNotifications(notificationsObj: {[type: string]: object}): object[] | boolean {
  if (_.isEmpty(notificationsObj)) {
    return false;
  } else {
    // note: lodash map will turn an object into an array
    return _.map(notificationsObj, (notification, type) => {
      return {...notification, type};
    });
  }
}

注意:与原始解决方案相比,我还避免了对原始通知对象进行变异。如果你依赖于发生的突变,那么你应该将该部分改变回去。

关于map的想法和注释都很好地了解。同样,这一点也值得一提。关于地图的想法和注释都很值得一提。我也这么认为。
const notificationsArray: object[] | boolean = []; // cannot be reassigned
_forEach(notificationsObj, function(notification, type) { // Culprit
  notification['type'] = type;
  notificationsArray.push(notification); // no error
});
notifications = notificationsArray; // assignment works
import * as _ from 'lodash';

function getNotifications(notificationsObj: {[type: string]: object}): object[] | boolean {
  if (_.isEmpty(notificationsObj)) {
    return false;
  } else {
    // note: lodash map will turn an object into an array
    return _.map(notificationsObj, (notification, type) => {
      return {...notification, type};
    });
  }
}