typescript - TypeScript:在对象之间转换元组的类型安全方式?
问题描述
在最近的一个项目中,我有很多基本上命名为元组的类,我经常发现自己需要在这些对象和元组之间进行转换。这意味着,我基本上有很多这样的功能:
const tupleToFoo = ([a, b, c]) => new Foo(a, b, c)
const fooToTuple = (foo) => [foo.a, foo.b, foo.c]
我可能应该把它留在那里,但我忍不住想知道是否有更通用的方法来编写这段代码。这是我想出的:
type AnyConstructor<T> = { new (...args: any[]): T }
type KeysOf<T> = ReadonlyArray<keyof T>
type Lookup<T, K> = K extends keyof T ? T[K] : never
type UnionFromInterface<T, K extends KeysOf<T>> = T[K[number]]
type TupleFromInterface<T, K extends KeysOf<T>> = {
[I in keyof K]: Lookup<T, K[I]>
}
function construct<T, K extends ReadonlyArray<keyof T>>(
C: AnyConstructor<T>
): (t: UnionFromInterface<T, K>[]) => T {
return t => new C(...t)
}
function deconstruct<T, K extends ReadonlyArray<keyof T>>(
D: K
): (o: T) => UnionFromInterface<T, K>[] {
return o => D.map(k => o[k])
}
function tupleToUnions<T, K extends ReadonlyArray<keyof T>>(
t: TupleFromInterface<T, K>
): UnionFromInterface<T, K>[] {
return t.map(i => i as UnionFromInterface<T, K>)
}
// This is particularly bad... :(
function unionsToTuple<T, K extends ReadonlyArray<keyof T>>(
u: UnionFromInterface<T, K>[]
): TupleFromInterface<T, K> {
return (u as unknown) as TupleFromInterface<T, K>
}
function instanceToTuple<T, K extends ReadonlyArray<keyof T>>(
T: (o: T) => UnionFromInterface<T, K>[]
): (o: T) => TupleFromInterface<T, K> {
return o => unionsToTuple(T(o))
}
function tupleToInstance<T, K extends ReadonlyArray<keyof T>>(
O: (t: UnionFromInterface<T, K>[]) => T
): (t: TupleFromInterface<T, K>) => T {
return t => O(tupleToUnions(t))
}
可以按如下方式使用:
class Person {
static Keys = ['name', 'hobbies'] as const
name: string
hobbies?: string[]
constructor(name: string, hobbies?: string[]) {
this.name = name
this.hobbies = hobbies
}
}
const tupleToPerson = tupleToInstance(
construct<Person, typeof Person.Keys>(Person)
)
const personToTuple = instanceToTuple(
deconstruct<Person, typeof Person.Keys>(Person.Keys)
)
const p = new Person('John Doe', ['yodeling'])
const t = personToTuple(p)
const q = tupleToPerson(t)
console.log(p, t, q)
虽然这“有效”,但问题在于它根本不是类型安全的。感觉应该有一种类型安全的方式来执行此操作,因为所有必要的信息在编译时都可用。因此,我很好奇是否有人知道一种类型安全的方法来实现这样的东西?
解决方案
推荐阅读
- ios - 在 Flutter 应用中显示自动强密码 iOS
- ios - 可以在 iOS 中使用 VB.NET 应用程序吗?
- python - 如何在熊猫数据框中删除重复项但根据特定列值保留行
- python - pre_delete 中的 Django FOREIGN KEY 约束失败
- c# - 如何使用 .NET 5 保存带有水印文本的 GIF
- wordpress - WordPress页面模板元素问题
- swift - Firebase 和 Swift:数组未正确插入
- ruby-on-rails - 有没有办法在 ahoy_events 表中更新或随着时间的推移跟踪事件?
- typescript - 有没有办法检测所有使用硬编码字符串而不是 i18n 翻译的打字稿文件?
- r - 有没有办法在 R(多 DV 和多 IV)中执行多变量 glm?