【问题标题】:Inferring types of deeply nested object in Typescript在 Typescript 中推断深度嵌套对象的类型
【发布时间】:2020-02-15 12:31:28
【问题描述】:

我正在尝试创建一个函数,可以安全地查找深度嵌套对象中的属性(在本例中为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; }; }'.

似乎无法使用联合类型查找联合类型,并且中途需要某种推理。

有什么想法吗?

【问题讨论】:

  • this 适合您吗?我不知道为什么你有这些条件类型,但我倾向于避免它们并使用通用查找。
  • 哦,这看起来比我预期的要清晰得多!准备将此作为正确答案。谢谢!

标签: typescript lookup type-inference


【解决方案1】:

我倾向于避免使用所有条件类型,因为编译器无法很好地推理它们,而且看起来你不需要它们。除了type Foo&lt;T&gt; = T extends U ? F&lt;T&gt; : never,你可以只使用constrainT,比如type Foo&lt;T extends U&gt; = Foo&lt;T&gt;,这对于编译器来说更直接。

这里的解决方案可能是使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];

这里我们说tTheme 类型,name 是某种泛型类型K 被限制为keyof Themestyle 是某种泛型类型S 被限制为@ 987654337@,而mod 是一些泛型类型M 被限制为keyof Theme[K][S]。这允许t[name][style][mod] 编译时没有错误,getStyle() 的返回类型被推断为Theme[K][S][M],这意味着输出也将是相当强的类型:

const sm = getStyle(theme, "button", "margin", "sm"); // string
const lg = getStyle(theme, "form", "padding", "lg"); // string

好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-08
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多