javascript - 在打字稿中实现安全导航
问题描述
最近,我在 Medium 中看到了Gidi Meir Morris的关于使用 ES6 的代理进行安全对象属性访问的以下文章。我真的很喜欢它,并想在我的 Typescript 项目中尝试一下可选嵌套对象,而不会丢失类型检查。
为了将可选的嵌套对象变成所有必需的,我使用以下类型:
export type DeepRequired<T> = {
[P in keyof T]-?: DeepRequired<T[P]>;
};
Gidi 在 typescript 中的代码(包括一些技巧......):
export interface Dictionary {
[key: string]: any;
};
const isObject = (obj: any) => obj && typeof obj === 'object';
const hasKey = (obj: object, key: string) => key in obj;
const Undefined: object = new Proxy({}, {
get: function (target, name) {
return Undefined;
}
});
export const either = (val: any, fallback: any) => (val === Undefined ? fallback : val);
export function safe<T extends Dictionary>(obj: T): DeepRequired<T> {
return new Proxy(obj, {
get: function(target, name){
return hasKey(target, name as string) ?
(isObject(target[name]) ? safe(target[name]) : target[name]) : Undefined;
}
}) as DeepRequired<T>;
}
使用示例:
interface A {
a?: {
b?: {
c?: {
d?: string
}
}
},
b: boolean,
c?: {
d: {
e: number
}
},
d?: Array<{e: boolean}>
}
const obj: A = {b: false};
const saferObj = safe(obj);
它在没有 TS 错误的情况下工作的场景:
test('should work for nested optional objects', () => {
expect(either(saferObj.a.b.c.d, null)).toEqual(null);
expect(either(saferObj.a.b.c.d, undefined)).toEqual(undefined);
expect(either(saferObj.a.b.c.d, 322)).toEqual(322);
});
test('should work for required members', () => {
expect(either(saferObj.b, null)).toEqual(false);
});
test('should work for mixed optional/required tree', () => {
expect(either(saferObj.c.d.e, null)).toEqual(null);
});
至于数组...
test('should work for arrays', () => {
expect(either(saferObj.d[0].e, null)).toEqual(null);
});
TS 编译器抛出以下错误:
[ts] Element implicitly has an 'any' type because type 'DeepRequired<{ e: boolean; }[]>' has no index signature.
知道我怎样才能使这个适用于数组吗?
解决方案
您的代码将在 Typescript 2.9 及更高版本上正常工作,因为在 Typescript 2.9 中,keyof
运算符包括数字和符号键以及之前由keyof
. 游乐场链接
如果您出于某些原因想要坚持使用 2.8,您可以使用在DeepRequired
使用条件类型时显式处理数组的解决方法。
export type DeepRequired<T> = {
[P in keyof T]-?: T[P] extends Array<infer U>?Array<DeepRequired<U>>: DeepRequired<T[P]>;
};
推荐阅读
- django - Django、docker、PostGIS 中的错误:服务器是否在本地运行并接受 Unix 域套接字“/var/run/postgresql/.s.PGSQL.5432”上的连接?
- python - 如何将模式问题的行添加到python中的列表中
- python - 如何访问视图中的 django 模型字段?
- python - Selenium - Instagram 机器人:点击照片后关注用户
- flutter - ThemeData(primaryColor: Colors.red) 和提供 ColorScheme.primary 有什么区别
- angular - 未捕获(承诺):错误:未找到名称“ngForm”的导出
- java - 找不到按钮 Selenium Webdriver
- python - Azure Functions:执行函数时出现异常:Functions.x <--- 结果:失败异常:ModuleNotFoundError:没有名为“_cffi_backend”的模块
- regex - StandardSQL:我只想在括号内提取
- android - 我在检查我的电子邮件字段时遇到问题