我正在玩一个示例,该示例对对象的属性可能如何相互引用施加了限制。一个假定的用例正在创建一个“模式”类型,其中包含可以关联的“表”类型。
四处游荡的我做了以下事情:
type Db<P extends Db<P>> = {
[K: string]: Table<P>;
};
type Table<P extends Db<P>> = {
refs: keyof P;
};
我想推断出最终类型并以有趣的方式重复使用它们,因此我创建了两个实用函数:
const schema = <TDb extends Db<TDb>>(db: TDb) => ({});
const table = <T extends Table<TDb>, TDb extends Db<TDb>>(tbl: T): T => ({} as T);
这个想法是在schema
函数中定义一个模式作为参数,并使用table
函数定义子表。我希望将ref
属性限制为我们已经在架构中定义的表的键。
令我惊讶的是(和打字稿的功劳)将架构写为文字可以工作:
schema({
foo: {
refs: 'bar', // Validated correctly, and intellisense suggests 'foo' | 'bar'.
},
bar: {
refs: 'foo',
},
});
但是,当我尝试使用表实用程序功能时,我失去了智能感知的优势:
schema({
foo: table({
refs: 'bar', // Validated correctly, but no intellisense completion suggestions.
}),
bar: {
refs: 'foo',
},
});
如果我将refs属性bar
更改为baz
之类的无效内容,则打字稿会抱怨。显然,它知道它应该是foo
或bar
,所以我猜想它是从所需的table
函数的返回类型推断模式类型的。
我想知道为什么它不建议他们?
我为想要试用的人设置了一个here游乐场: