我正在尝试创建一个泛型类型,该泛型类型被限制为另一个特定类型的子集。不应允许它添加新属性或重写现有属性的类型,但应允许它仅实现指定类型的子集。这是我所期望的:
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
做的事情,我不想要:
- 允许声明其他属性(案例 3 有效(
- 强制执行
Foo
的所有属性(案例 1 无效(
extends Partial<Foo>
做的事情,我不想要:
- 允许声明其他属性(案例 3 有效(
- 可以
undefined
所有属性的值
当前状态
我创建了一个类型,该类型创建了另一种类型的子集:
type Subset<T extends S, S> = Pick<T, keyof S>
但我无法让它作为类的约束......
我们可以创建一个不允许指定任何额外成员的限制,方法是强制要求如果存在任何额外的属性,则它们属于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 }>()
游乐场链接