我正在尝试创建一个泛型类型,它被约束为另一个特定类型的子集。不应该允许添加新属性或覆盖现有属性的类型,但应该允许它仅实现指定类型的子集。这就是我所期望的:
type Foo = { a: string; b: number; }
// Case1: valid
new MyClass<{ a: string }>()
// Case2: invalid (does not exist in both types)
new MyClass<{ b: number }>()
// Case3: invalid (does not exist in both types)
new MyClass<{ c: string }>()
// Case4: invalid (does not exist in both types)
// invalid (wrong type of a)
new MyClass<{ a: number }>()
// Case5: invalid (wrong type of a)
new MyClass<{ a: undefined }>()
new MyClass<{ a: null }>()
我需要的是这样的事情:
// Pseudo code (subsets does not exist):
class MyClass<T subsets Foo> {}
extends Foo
做的事情,我不想要的事情:
Foo
的所有属性(案例1无效) extends Partial<Foo>
所做的事情,我不想要的事情:
undefined
当前状态
我创建了一个创建另一种类型子集的类型:
type Subset<T extends S, S> = Pick<T, keyof S>
但是我无法将它作为类的约束来使用...
答案 0 :(得分:1)
我们可以创建一个不允许指定任何额外成员的限制,强制要求如果存在任何额外属性,则它们的类型为never
。我们可以使用Exclude<keyof T, keyof S>
执行此操作,仅获取额外的密钥和Record
:
type Foo = { a: string; b: number; }
type Subset<T, S> = Pick<S, Extract<keyof T, keyof S>> & Partial<Record<Exclude<keyof T, keyof S>, never>>
class MyClass<T extends Subset<T, Foo>> {
constructor(public t?:T){
if(t == null) return;
// t has no accessible members as far as the compiler is concerned
// but we can assign it to Partial<Foo> and access fields like this
let d: Partial<Foo> = t;
d.a // works
}
}
// Case1: valid
new MyClass<{ a: string }>()
// Case2: invalid (does not exist in both types)
new MyClass<{ b: number }>()
// Case3: invalid (does not exist in both types)
// This would be invalid under extends Partial<Foo> also
new MyClass<{ c: string }>()
// Case3b: invalid (has extra props)
// This would be valid under extends Partial<Foo> but is not under Partial<Foo> & Record<Exclude<keyof T, keyof Foo>, never>
new MyClass<{ a: string, c: string }>()
// Case4: invalid (does not exist in both types)
// invalid (wrong type of a)
new MyClass<{ a: number }>()
// Case5: invalid (wrong type of a) only with strict null checks !
new MyClass<{ a: undefined }>()
new MyClass<{ a: null }>()