下面是我正在使用的模式库的一个简化示例(playground link):
type Column<T extends string = string, V = unknown> = {
internalType: T
value: V
}
type Table = {
[column: string]: Column
}
type Row<T extends Table> = {
data: {
[C in keyof T]: T[C]['value']
}
}
type NumberColumn = Column<'int', number>
type StringColumn = Column<'str', string>
type BooleanColumn = Column<'bool', boolean>
type ReferenceColumn<T extends Table = Table> = Column<'ref', Row<T>> & { table: T }
type FooTable = {
active: BooleanColumn
priority: NumberColumn
}
type BarTable = {
name: StringColumn
foo: ReferenceColumn<FooTable>
}
type PickColumns<T extends Table, ColumnType extends Column> = Pick<
T,
{
[C in keyof T]: T[C] extends ColumnType ? C : never
}[keyof T]
> & {
[column: string]: ColumnType
}
function columnFromReferenceTable<
T extends Table,
RefCols extends PickColumns<T, ReferenceColumn> = PickColumns<T, ReferenceColumn>,
RefColName extends keyof RefCols = keyof RefCols,
RefCol extends RefCols[RefColName] = RefCols[RefColName],
RefTable extends RefCol['table'] = RefCol['table'],
RefTableColName extends keyof RefTable = keyof RefTable
>(referenceColumn: RefColName, referenceTableColumn: RefTableColName) {
referenceColumn
referenceTableColumn
}
columnFromReferenceTable<BarTable>('foo', 'active') // Valid
columnFromReferenceTable<BarTable>('foo', 'priority') // Valid
columnFromReferenceTable<BarTable>('foo', 'wrong') // Shouldn't be valid
基本上,有些表模式可能包含引用其他表模式的列。目标是有一个接受两个字符串的函数,其中第一个字符串是一个表中引用列的名称,第二个字符串是被引用的另一个表中任何列的名称。
问题是:我无法正确约束第二个参数的字符串值。第一个参数约束正确,但第二个参数可以是任何字符串值,这是不正确的。
我试图尽可能地简化这个例子,而不是过于做作,我知道函数的类型签名是不必要的冗长,但希望它能帮助读者理解我是如何尝试导航类型的。
2条答案
按热度按时间axr492tv1#
由于不支持部分类型推理,因此当您只使用一个泛型参数调用函数时,将使用其他泛型参数的默认值,正如您所观察到的,这将导致示例基本上没有类型检查。
我们通常绕过这个问题的方法是 * 咖喱 * 函数:
再插入一对括号,我们就可以开始了:
Playground
P.S.您现在可以删除类型参数的默认值,它仍然可以工作。
wooyq4lh2#
正如另一个答案指出的,我的问题是由于TypeScript当前缺少类型参数partial type inference,因为
BarTable
作为类型参数传递,而没有其他参数,所以使用约束较少的默认类型。我没有使用另一个答案提供的快速解决方案,而是选择了一个不同的解决方案,它通过将表作为对象传入来完全避免部分类型推理问题,这支持所有类型参数的完全推理:
在我的图书馆里,table已经是对象了,所以这个设计提供了比咖喱更好的DX。