对于Angular ngrx应用程序使用Typescript,我必须做很多检查,我访问或传递的值是null / undefined,例如在可能存在的列表上调用.map()。
要走的路是什么?确保整个Codebase nevererver移交null?在每次调用之前检查,以防生成像空列表这样的空对象?或者是否有某种类型的null-object模式用于函数式编程?
帕维尔的@Comment: 我们有一个可以选择的项目列表,如果是这样,详细信息将在视图中展开。在我看来,当删除列表中已打开的项目时,应用程序崩溃了,因为对已打开项目的引用设置为null。我通过对我编写的所有选择器进行空检查来修复此问题,以便修复应用程序崩溃,正如我在许多其他选择器中看到的那样,他们在浏览器中使用应用程序本地状态。答案 0 :(得分:3)
这里有一些众所周知的模式可以提供帮助。
Maybe / Option是一种在TypeScript中具有以下结构的和类型:
type Maybe<T> = T | void;
您可以在typescript user manual中了解有关实施该问题的更多信息,只需ctrl-f
即可查看&#39;因为他们似乎出于某种原因避开了片段标识符。
Maybe(其中一个反正)的问题是它很快变成了病毒,它接管了整个代码库,每个值都变成了一个Maybe。如果没有模式匹配,处理这一点尤其烦人(打字稿手册中的例子非常详细)。一个更好的选择恕我直言,因为JavaScript / TypeScript缺少任何类型的存在运算符是编写没有空检查的函数,然后使用执行检查的函数来装饰它们。
function argCheckDecorator(f) {
return function(...args) {
// Functions have a length property that is their arity.
// You could modify this to only check the first argument,
// not check arity for varargs, etc.
if (
args.length === f.length &&
args.every(arg => arg !== null && arg !== undefined)
) {
return f.apply(this, args);
} else {
// optionally warn console
// console.warn(`Called ${f.name} with invalid arguments ${args}.`);
return null;
}
}
}https://www.destroyallsoftware.com/talks/boundaries
这里显而易见的问题是你正在进行相当广泛的运行时检查(首先是AFAIK导致你提出问题的原因),而不是依靠编译器。不幸的是,在JavaScript / TypeScript中,您的选项总是有限的,没有办法保证对DOM的调用永远不会返回null
或者对象属性访问永远不会返回{{1} (至少如果你正在解析一个对象的JSON HTTP响应)。
至少使用函数装饰器,您可以将每个函数的空值检查移出。将我的高阶函数转换为TypeScript装饰器留给读者练习。
举一个例子来说明我在评论中谈到的内容:
undefined
同时,回到牧场......
// messy-shell.js
// All DOM mutation, AJAX calls, optional params, null checks, etc.
// go here.
import * as ideal from './perfect-world.js';
const getDOMElement = (selector, element=document) => {
return (selector && element instanceof HTMLElement) ?
ideal.getDOMElement(selector, element) : null;
};
const getAJAXData => (url, method='GET', params) => {
let p = params ? // IRL you'll want to do more checking than this
fetch(url, { body: params, method }) :
fetch(url, { method });
return p.then(resp => {
if (resp.statusCode >= 200 && resp.statusCode < 400) {
return resp.json();
} else {
throw new Error(`${resp.statusCode} response.`);
}
}).then(data => {
if (data && (data.length || Object.keys(data).length)) {
return ideal.processAJAXData(data);
} else {
throw new Error('Empty data response.');
}
}).then(processedData => {
// update DOM here, or skip this and just return Promise<processedData>
}).catch(err => {
// do error handling
});
};
现在你不必为每个小功能都想要这个级别的仪式,但是如果你的团队/代码库/问题领域足够大,你可能会。一些不错的属性不属于此:
您可能还想检查this。