我正在尝试创建一个函数,该函数可以安全地在深度嵌套的对象(在这种情况下为theme
)中查找属性。我应该指出,我不想静态定义其类型,因为它们旨在经常更改,因此使用typeof
此函数接受对象本身和3个键,但是问题是-我无法正确推断所有类型的类型。
const theme = {
button: { margin: { sm: "sm" } },
form: { padding: { lg: "lg" } }
}
type Theme = typeof theme
type CompoName = keyof Theme;
// styles of component with give key
// { margin: ..., padding: ... }
type CompoStyle<C> = C extends CompoName ? keyof Theme[C] : never;
// string
// S = margin, padding
type CompoStyleMod<C, S> = S extends keyof CompoStyle<C>
? CompoStyle<C>[S]
: never;
const getStyle = (
t: Theme,
name: CompoName,
style: CompoStyle<typeof name>,
mod: CompoStyleMod<CompoName, typeof style>
) => {
return t[name][style][mod]
}
TypeScript 3.6.3中的结果:
Element implicitly has an 'any' type because expression of type '"margin" | "padding"' can't be used to index type '{ margin: { sm: string; }; } | { padding: { lg: string; }; }'.
Property 'margin' does not exist on type '{ margin: { sm: string; }; } | { padding: { lg: string; }; }'.
看起来不可能用联合类型和中途需要某种推断来查找联合类型。
有什么想法吗?
答案 0 :(得分:1)
我倾向于避免使用所有条件类型,因为编译器无法很好地推论它们,并且看起来您不需要它们。除了type Foo<T> = T extends U ? F<T> : never
之外,您还可以像T
那样constrain type Foo<T extends U> = Foo<T>
,对于编译器来说更简单。
这里的解决方案可能是使getStyle()
generic具有足够的类型参数,以使编译器理解每个参数都在钻取到对象及其属性looking up中。像这样:
const getStyle = <
K extends keyof Theme,
S extends keyof Theme[K],
M extends keyof Theme[K][S]
>(t: Theme, name: K, style: S, mod: M) => t[name][style][mod];
这里我们说t
的类型为Theme
,name
的类型为一般类型K
约束为keyof Theme
,{{1} }具有约束到style
的某种通用类型S
,而keyof Theme[K]
具有约束到mod
的某种通用类型M
。这使得keyof Theme[K][S]
可以无错误地进行编译,并且将t[name][style][mod]
的返回类型推断为getStyle()
,这意味着输出也将被相当强地键入:
Theme[K][S][M]
好的,希望能有所帮助。祝你好运!