我有几个简单的类型:
export const structureTypes = ["atom", "molecule"] as const
export type Structure = typeof structureTypes[number]
export const atomTypes = [
"hydrogen",
"oxygen",
"argon",
] as const
export const moleculeTypes = [
"water",
"methane",
] as const
export type AtomType = typeof atomTypes[number]
export type MoleculeType = typeof moleculeTypes[number]
我希望能够使用这些来约束一个对象的可能输入,该对象保存每种类型的ID:
export type StructureIdCache = {
[key in Structure as string]: {
[key in AtomType | MoleculeType]: string
}
}
这是可行的,但是在第二层允许AtomType | MoleculeType
允许我使用"water"
作为一个键,当第一层键是"atom"
时,这是无效的。我如何修改类型以允许在对象的第二层只输入允许的名称?
我尝试过创建条件类型:
export type StructureType<T> = T extends Atom ? AtomType : MoleculeType
这适用于创建特定类型:
type AtomTypeNames = StructureType<Atom>
type MoleculeTypeNames = StructureType<Molecule>
但不允许我约束函数的输入:
export const getTypeId = async (
c: Context,
type: Structure,
name: StructureType<typeof type> // <-- this should restrict name inputs but does not
): Promise<string> => {
// do something
}
如何根据传递给type
的字符串值限制name
的有效输入?
1条答案
按热度按时间bxgwgixi1#
一种方法是写出一个
const
Assert的对象,其类型捕获Structure
和关联的AtomType
/MoleculeType
之间所需的关系:并使用它生成表示以下关系的mapped type:
现在,我们不再试图让generic函数依赖于conditional type(这对编译器来说本质上是不透明的,也很难推理),而是让它依赖于indexed access type(对应于一个属性查找):
因此
type
是StructureType
的某个键类型K
(即,"atom"
或"molecule"
),并且name
是StructureType
的对应属性类型StructureType[K]
(因此,例如,如果K
是"atom"
,则StructureType[K]
是"氢")。|"氧气"|你不一定要在对象中查找属性,但是编译器可以很好地推理泛型对象查找,并且通过使用这些术语来描述操作,编译器不会出错。我们来试试看:
看起来不错。在第一种和第二种情况下,
K
被推断为"atom
",因此"hydrogen"
可接受,但"water"
不可接受。在第三种情况下,K
被推断为"molecule"
,因此"water"
可接受。因此,type
和name
之间的关系是强制的,至少对于这些使用情况。(在某些情况下,
K
被推断为一个联合类型,然后StructureType[K]
也将是一个联合类型,并且这种关系可能不会以您想要的方式强制执行。但是对于泛型函数的大多数用户来说,这类问题通常不是什么大问题,所以我不会在这里讨论如何处理它。)Playground代码链接