typescript - 使用 TypeScript 描述在赋值时更改其属性类型的代理对象
问题描述
设置
事实证明,向 TypeScript 编译器描述代理对象的工作方式有点挑战性。以带有 setter 的 Proxy 的情况为例,该 setter 将输入中的任何对象也转换为递归代理它们,TypeScript 理解这一点并允许直接分配而不需要首先强制最终递归代理会非常好目的。这是一个示例,它也在TypeScript 操场上运行:
interface SimpleObject {
[index: string]: any
}
type ProxyObject<T> = {
[K in keyof T]: T[K] extends SimpleObject ? ProxyObject<T[K]> : T[K]
} & {
isProxy: true
}
function createProxy<T extends SimpleObject>(obj: T): ProxyObject<T> {
const proxyObject = Object.create(obj, {})
for (const key in obj) {
proxyObject[key] = (typeof obj[key] === 'object') ? createProxy(obj[key]) : obj[key]
}
return new Proxy(proxyObject, {
get (...args) {
// some side effects here perhaps
console.log(`fetchin value for ${args[2]}`)
return Reflect.get(...args);
},
set (target, property, value) {
const setTo = (typeof value === 'object' && !value.isProxy) ? createProxy(value) : value
return Reflect.set(target, property, setTo)
}
})
}
const proxied = createProxy({
text: 'hello world',
nested: {
money: 345
}
})
// This works because it's initially declared as a string
proxied.text = 'Another value'
// This wont work because text is a string, this is good!
// proxied.text = 123
// This will work!
proxied.nested.money = 123
// This works
proxied.nested = createProxy({ money: 555 })
// This will not work because
// > Type '{ money: number; }' is not assignable to type 'ProxyObject<{ money: number; }>'
proxied.nested = { money: 555 }
问题
理想情况下,您将有一种方法可以通知 TypeScript 编译器proxied.nested
将自动转换为正确的类型(即ProxyObject<{ money: number}>
)。您可以在 ProxyObject 定义中使用联合运算符来允许这样做:
type ProxyObject<T> = {
[K in keyof T]: T[K] extends SimpleObject ? ProxyObject<T[K]> | T[K] : T[K]
} & {
isProxy: true
}
但这并不能真正解决proxied.nested
更改输入类型的问题,相反,所有对象ProxyObject
都不再确定它们是 SimpleObject 还是 ProxyObject,因此您必须不断地嗅出它。
问题: 有什么方法可以告诉 TypeScript 这个属性可以分配一个联合(多种类型),但读取时它的值始终是单一类型?
解决方案
推荐阅读
- ldap - Artifactory ldaps 错误的 url/端口
- java - 在Java中通过索引查找第一对最大和
- java - Java 空 Optional 的类型是什么?
- opengl - C++ OpenGL, using more than one uniform
- c# - Visual Studio Extension 在调试时工作,但是当我安装 VSIX 时它不工作
- android - 无法为模拟器构建应用程序
- sql - 如何创建一个新表,基于具有动态内容的现有表,但将历史记录保留在新表中?
- excel - VBA Excel - 循环输出结果列组为 3
- c# - 如果打开了 CSV/Excel 文件,则使用 MessageBox 通知用户并终止应用程序的其余执行 [C# - WPF 应用程序]
- firebase - 用户注册firebase时如何保存名称?