Typescript部分但不是完整对象本身

Typescript部分但不是完整对象本身,typescript,mapped-types,Typescript,Mapped Types,假设我有一个对象: type Obj={a:string,b:string,c:string} 使用Partial,TS为您提供对象属性的所有可能组合,包括对象的完整形式。在我的例子中,我想排除完整对象(如果可能的话,也包括空对象) 所以我想: {}//❌ {a:string}//✅ {b:string}//✅ {c:string}//✅ {a:string,b:string}//✅ {a:string,c:string}//✅ {a:string,b:string,c:string}//❌

假设我有一个对象:

type Obj={a:string,b:string,c:string}
使用
Partial
,TS为您提供对象属性的所有可能组合,包括对象的完整形式。在我的例子中,我想排除完整对象(如果可能的话,也包括空对象)

所以我想:

{}//❌
{a:string}//✅
{b:string}//✅
{c:string}//✅
{a:string,b:string}//✅
{a:string,c:string}//✅
{a:string,b:string,c:string}//❌

如何实现这一点?

要实现此行为,需要为
Obj
类型创建两个约束。第一种应排除“满”类型,第二种应排除“空”类型


第一个约束意味着至少有一个属性的类型应该是
未定义的
(或者根本不存在)。因此,我们需要一个类型的并集,其中至少有一个属性符合约束

首先,我们必须映射初始类型,以获得省略一个属性的所有可能的类型组合(注意
修饰符-它确保允许可变数量的属性),并使用
keyof T
提取我们的并集:

{
[P in keyof T]:{
[K in Exclude]?:T[P]
}
}[keyof T]
如果我们不这样做,我们仍然可以指定所有属性,因此我们需要显式地告诉编译器不允许第三个属性<代码>?修饰符确保我们可以省略属性:

类型NotAll={
[P in keyof T]:{
[K in Exclude]?:T[P]
}&{[M in P]?:never}
}[keyof T]

第二个约束意味着至少应该定义一个属性。逻辑基本相同,但这一次对于每个属性,我们都有一种类型的所有属性,除了一个设置为可选的属性与需要此属性的类型相交:

类型至少为一个={
[P in keyof T]:{
[K in Exclude]?:T[P]
}&{[M in P]:T[M]}
}[keyof T];
最后,我们需要将第二个约束与第一个约束结合起来。由于第一个约束为我们提供了一个允许类型的并集,因此应该对该并集的每个成员应用
AtLeastOne

类型NotAll={
[P in keyof T]:至少一个&{[M in P]?:never}
}[keyof T];
就这样,让我们测试一下我们的类型:

型式试验=NotAll;
常量为空:test={}//错误
常数a:test={a:“test”}//好啊
常数ab:test={a:“test”,b:“test”}//好啊
常量bc:test={b:“test”,c:“test”}//好啊
常量abc:test={a:“test”,b:“test”,c:“test”}//错误

魔法!谢谢你的详细解释!然而,我仍然无法理解这一点:
[K in Exclude]?:t[P]
其中
P
是我们正在迭代的当前属性。它被排除在外,但同时被引用(通过
T[P]
)?这怎么可能?这里没有魔法:)
P
在外部映射类型中被引用,因此在内部映射类型中仍然可以访问。而
Exclude
只给了我们一个很好的键组合,除了
P
我明白了!所以我猜,然后将
T[P]
更改为
T[K]
会得到类似的结果(事实确实如此)。再次感谢:)@JihadWaspada-NP。Re:可互换性-是的,您可以同时使用这两种方法(从表面上看,
T[K]
在语义上更为正确,尽管会产生相同的结果)