Typescript 按接口深度拾取
假设我们有一个目标Typescript 按接口深度拾取,typescript,typescript-typings,Typescript,Typescript Typings,假设我们有一个目标 让obj={ 福:‘福’, 酒吧:“酒吧”, 信件:{ a:‘一些a’, b:‘一些b’, } } 我们想根据定义进行深入挑选: let投影={ 傅:1,, 信件:{ b:1 } } 它将产生: 让结果={ 福:‘福’, 信件:{ b:一些b' } } 问题不在于如何在javascript中实现这一点,而是非常简单。但是TypeScript定义是什么样子的 类型t项目={ [key in U]?:T[key]扩展对象?T项目:编号; } 函数选取( obj:T, 投影:
让obj={
福:‘福’,
酒吧:“酒吧”,
信件:{
a:‘一些a’,
b:‘一些b’,
}
}
我们想根据定义进行深入挑选:
let投影={
傅:1,,
信件:{
b:1
}
}
它将产生:
让结果={
福:‘福’,
信件:{
b:一些b'
}
}
问题不在于如何在javascript中实现这一点,而是非常简单。但是TypeScript定义是什么样子的
类型t项目={
[key in U]?:T[key]扩展对象?T项目:编号;
}
函数选取(
obj:T,
投影:t投影
):选择{
返回null;
}
这只会导致顶级pick,
字母
字段包括a
和b
函数的实现可能有点重要,因为我在这里提出的键入中可能存在需要测试的边缘情况。希望您可以将此作为起点并进行调整以获得边缘案例
首先,有必要描述投影
,这是投影的可接受类型
对于T
类型的obj
值:
type Projection<T extends object> = {
[K in keyof T]?: T[K] extends object ? Projection<T[K]> : number
};
基本上,我们正在浏览T
和p
的常用键。如果P
中的属性是一个数字
,我们将从T
输出该属性。如果它是一个对象
,那么我们递归到T[K]
和P[K]
并重复。唯一看起来奇怪的部分是结尾的extensedinfero..
位。这是一个迫使编译器急切地评估输出类型而不是延迟它的技巧。如果您想要像{foo:string;letters:{b:string}}
这样的输出类型,而不是DeepPickByProjection
,那么您需要这样的技巧。有关其工作原理的详细信息,请参阅
好的,让我们看看打字是否有效:
function pick<T extends object, P extends Projection<T>>(
obj: T,
projection: P
): DeepPickByProjection<T, P> {
return null!;
}
const result = pick(obj, projection);
/* const result: {
foo: string;
letters: {
b: string;
};
} */
函数选取(
obj:T,
投影:P
):DeepPickByProjection{
返回null!;
}
常量结果=拾取(对象、投影);
/*常数结果:{
foo:string;
信件:{
b:弦;
};
} */
看起来不错。result
的输出类型与投影过滤的obj
的输入类型相同。万岁
记住,虽然可能有很多边缘情况。对于初学者,我会关心可选属性、联合属性和数组值属性,并确保有人不希望传入类似{letters:1}
的内容,意思是“在此处复制整个子树”,因为我认为上面的键入禁止这样做。正如我所说的,这应该被认为是一个启动点,而不是您的用例的一个生产就绪的插件
太棒了,非常感谢你的帮助。我添加了
(TProjection | number)
以允许{letters:1}
和数组支持,现在我们所有的mongodb投影都是类型安全的-请不要编辑您的问题以包含答案-这只会让读者对问题的含义感到困惑。人们已经可以在下面找到答案。我已经回滚了您的编辑。@kaya3但是我的编辑没有复制过去,我已经为各种情况添加了额外的支持-这些对于发现下面的答案的人来说绝对有用,因为下面的答案有一些限制。然后将您自己的答案作为答案发布。这不是问题的一部分。
function pick<T extends object, P extends Projection<T>>(
obj: T,
projection: P
): DeepPickByProjection<T, P> {
return null!;
}
const result = pick(obj, projection);
/* const result: {
foo: string;
letters: {
b: string;
};
} */