- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试用更具体的类型替换以下函数中的字符串类型,以确保类型安全的属性访问:
import {get} from 'lodash';
const obj = {
foo: 'foo',
bar: {
a: 'Hello',
b: {c: 'World'}
}
};
function factory(namespace?: string) {
return function getter(key: string) {
return get(obj, [namespace, key].filter((part) => part != null).join('.'));
};
}
const getter = factory('bar');
getter('b.c'); // 'World'
点符号表示嵌套属性访问。它可以同时出现在 namespace
中。以及 key
.
到目前为止,我发现我可以输入 namespace
使用此实用程序:
type NestedKeyOf<ObjectType extends object> =
{
[Key in keyof ObjectType & (string | number)]: ObjectType[Key] extends object
? `${Key}` | `${Key}.${NestedKeyOf<ObjectType[Key]>}`
: `${Key}`
}[keyof ObjectType & (string | number)];
用法:namespace?: NestedKeyOf<typeof obj>
.
然而,我正在努力想出一个自动分配给 key
的动态类型.
另外两个要求是:
可以假设对象中只有对象和字符串存在,没有其他。
// Test cases
// Should pass
factory()('foo')
factory('bar')('a')
factory('bar')('b.c')
// Invalid property access
// @ts-expect-error
factory('baz')
// @ts-expect-error
factory('bar')('d')
// Only partial namespaces are allowed
// @ts-expect-error
factory('foo')
// Getter calls need to resolve to a leaf string
// @ts-expect-error
factory('bar')('b')
任何帮助将不胜感激!非常感谢!
最佳答案
我不敢相信这种可憎的做法真的有效:
function factory<NestedKey extends NestedKeyOf<typeof obj>>(namespace?: NestedKey) {
return function getter<
TargetKey extends
(NestedKey extends undefined
? NestedKeyOf<typeof obj>
: NestedKeyOf<Get<typeof obj, NestedKey>>)
>(key: TargetKey): NestedKey extends undefined ? Get<typeof obj, TargetKey> : Get<typeof obj, `${NestedKey}.${TargetKey}`> {
return get(obj, [namespace, key].filter((part) => part != null).join('.'));
};
}
请允许我解释一下。首先,我在实现 NestedKeyOf 时遇到了很多麻烦 :(
我不得不重写它,因为它报告类型实例化太深,所以这是我的版本:
type NestedKeyOf<O> = O extends object ? {
[K in keyof O]: `${K & string}` | `${K & string}.${NestedKeyOf<O[K]>}`;
}[keyof O] : never;
它做同样的事情;只是写的不一样。接下来我们需要能够“深度获取”一个属性(模仿 lodash 的 get 函数):
type Get<O, P extends string> =
P extends `${infer Key}.${infer Rest}`
? Key extends keyof O ? Get<O[Key], Rest> : never
: P extends keyof O ? O[P] : never;
额外的 extends keyof O
是为了防止无效属性访问错误。
最后是我在上面展示的怪物。
我们需要存储namespace
是什么,所以我们使用泛型。有了这个恰本地命名为 NestedKey
的泛型,我们现在可以在 getter
的定义中使用它。
getter
也采用嵌套键。但是,当未提供 namespace
时,其类型会有所不同。
这就是 NestedKey extends undefined
存在的原因。如果不存在,则 key
应该是原始对象的嵌套键。否则,它是 namespace
指向的值的嵌套键,使用 Get
。
最后在返回值中,我们做同样的事情。如果 NestedKey
不存在,那么我们将深入获取目标键,否则,我们将深入获取嵌套键和目标键。
as const
断言是为了验证它实际上深度获取了正确的值。
根据新要求进行更新。我们需要一些新类型来告诉我们哪些键是对象,哪些是字符串:
type GetObjectKeys<O, K extends string> = {
[P in K]: Get<O, P> extends string ? never : P;
}[K];
type GetStringKeys<O, K extends string> = {
[P in K]: Get<O, P> extends string ? P : never;
}[K];
它们采用对象类型和一些潜在的键。它检查每个键的类型。对于对象,如果是字符串,则为never
,否则为P
。我们使用 never
因为下面我们将得到所有剩余键与 [K]
和 T | 的联合。从不
简化为T
。
然后由于 namespace
是可选的,它引入了一些困难。我的一个错误是认为如果未提供 namespace
,NestedKey
将是未定义的(因此之前的答案实际上是不正确的)。稍后会更正。
为了解决可选的 namespace
,我们将原始 factory
函数的参数 namespace
not 设为可选并重命名到 _factory
(内部/私有(private))。然后我们创建一个新的 factory
函数,像这样调用它:
function factory<NestedKey extends GetObjectKeys<typeof obj, NestedKeyOf<typeof obj>>>(namespace?: NestedKey) {
return _factory<
{ __private: typeof obj },
GetObjectKeys<typeof obj, NestedKeyOf<typeof obj>> extends NestedKey ? "__private" : `__private.${NestedKey}`
//@ts-ignore Unfortunately I don't think there is a good way to prevent this error
>({ __private: obj }, namespace ? `__private.${namespace}` : "__private");
}
它需要任何对象键,但如果未提供命名空间,它将创建默认为 __private
,因为我们将目标对象包装在另一个具有属性 __private
的对象中绕过 namespace 是可选的这一事实。将其视为委托(delegate)人。
现在修改后的 _factory
函数:
function _factory<Obj extends unknown, NestedKey extends NestedKeyOf<Obj>>(obj: Obj, namespace: NestedKey) {
return function getter<
TargetKey extends GetStringKeys<Get<Obj, NestedKey>, NestedKeyOf<Get<Obj, NestedKey>>>
>(key: TargetKey): Get<Obj, `${NestedKey}.${TargetKey}`> {
return get(obj, [namespace, key].filter((part) => part != null).join('.'));
};
}
此函数与原始函数大部分相同,只是现在它只需要生成字符串的键。处理可选 namespace
的部分被移动到新的 factory
函数中。
我本可以为 factory
和 _factory
选择更好的名称以避免混淆,但希望您已经足够了解我的情况。
顺便说一句,这是对****的过度设计;当你开始让类型像真正的代码一样工作时总是如此 😛
关于typescript - 分两步使用类型安全的属性访问递归解析对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71529277/
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 4 年前。 Improv
PowerShell Web Access 允许您通过 Web 浏览器运行 PowerShell cmdlet。它显示了一个基于 Web 的控制台窗口。 有没有办法运行 cmdlet 而无需在控制台窗
我尝试在无需用户登录的情况下访问 Sharepoint 文件。 我可以通过以下任一方式获取访问 token 方法一: var client = new RestClient("https://logi
我目前正在尝试通过 Chrome 扩展程序访问 Google 服务。我的理解是,对于 JS 应用程序,Google 首选的身份验证机制是 OAuth。我的应用目前已成功通过 OAuth 向服务进行身份
假设我有纯抽象类 IHandler 和派生自它的类: class IHandler { public: virtual int process_input(char input) = 0; };
我有一个带有 ThymeLeaf 和 Dojo 的 Spring 应用程序,这给我带来了问题。当我从我的 HTML 文件中引用 CSS 文件时,它们在 Firebug 中显示为中止。但是,当我通过在地
这个问题已经有答案了: JavaScript property access: dot notation vs. brackets? (17 个回答) 已关闭 6 年前。 为什么这不起作用? func
我想将所有流量重定向到 https,只有 robot.txt 应该可以通过 http 访问。 是否可以为 robot.txt 文件创建异常(exception)? 我的 .htaccess 文件: R
我遇到了 LinkedIn OAuth2: "Unable to verify access token" 中描述的相同问题;但是,那里描述的解决方案并不能解决我的问题。 我能够成功请求访问 toke
问题 我有一个暴露给 *:8080 的 Docker 服务容器. 我无法通过 localhost:8080 访问容器. Chrome /curl无限期挂断。 但是如果我使用任何其他本地IP,我就可以访
我正在使用 Google 的 Oauth 2.0 来获取用户的 access_token,但我不知道如何将它与 imaplib 一起使用来访问收件箱。 最佳答案 下面是带有 oauth 2.0 的 I
我正在做 docker 入门指南:https://docs.docker.com/get-started/part3/#recap-and-cheat-sheet-optional docker-co
我正在尝试使用静态 IP 在 AKS 上创建一个 Web 应用程序,自然找到了一个带有 Nginx ingress controller in Azure's documentation 的解决方案。
这是我在名为 foo.js 的文件中的代码。 console.log('module.exports:', module.exports) console.log('module.id:', modu
我试图理解访问键。我读过https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-se
我正在使用 MGTwitterEngine"将 twitter 集成到我的应用程序中。它在 iOS 4.2 上运行良好。当我尝试从任何 iOS 5 设备访问 twitter 时,我遇到了身份验证 to
我试图理解访问键。我读过https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-se
我正在使用以下 API 列出我的 Facebook 好友。 https://graph.facebook.com/me/friends?access_token= ??? 我想知道访问 token 过
401 Unauthorized - Show headers - { "error": { "errors": [ { "domain": "global", "reas
我已经将我的 django 应用程序部署到 heroku 并使用 Amazon s3 存储桶存储静态文件,我发现从 s3 存储桶到 heroku 获取数据没有问题。但是,当我测试查看内容存储位置时,除
我是一名优秀的程序员,十分优秀!