【问题标题】:Inferring types of non-leaf nodes of deeply nested object in Typescript在 Typescript 中推断深度嵌套对象的非叶节点类型
【发布时间】:2021-03-25 19:55:31
【问题描述】:

我一直在玩Inferring types of deeply nested object in Typescript

原始代码

const theme = {
    button: { margin: { sm: "sm" } },
    form: { padding: { sm: "sm1" } }
} as const;

type Theme = typeof theme;

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];

getStyle(theme, 'button', 'margin', 'sm');

我从原始示例中引入了一种变体 - 在我的代码中叶节点始终具有相同的结构 {sm: string}

我正在努力修改getStyle,使客户端只能指定2级密钥,并受益于节点结构始终相同的事实;

const getStyleNew = <
    K extends keyof Theme,
    S extends keyof Theme[K]
>(t: Theme, name: K, style: S) => t[name][style].sm;

不幸的是,这失败了:

Property 'sm' does not exist on type '{ readonly button: { readonly margin: { readonly sm: "sm"; }; }; readonly form: { readonly padding: { readonly sm: "sm"; }; }; }[K][S]'.

有没有办法让编译器相信修改后的函数中t[name][style]上sm可用?

Playground link

【问题讨论】:

    标签: typescript


    【解决方案1】:

    执行此操作的一种方法是将样式记录分配给具有sm 属性的对象,该属性是使用条件Index 类型键入的,以说明可能缺少sm。这甚至会推断出结果的确切文字类型,而不仅仅是string。这是一个通用的解决方案,但您也可以使用Theme 而不是T

    type Index<T, K> = K extends keyof T ? T[K] : undefined;
    
    const getStyleNew = <
      T,
      K extends keyof T,
      S extends keyof T[K]
    >(t: T, name: K, style: S) => {
      const {sm}: {sm: Index<T[K][S], 'sm'>} = t[name][style]
      return sm
    };
    
    const test1 = getStyleNew(theme, 'button', 'margin'); // inferred: test1: "sm"
    const test2 = getStyleNew(theme, 'form', 'padding'); // inferred: test2: "sm1"
    

    如果您查询没有sm 的样式记录(例如header: { fontSize: {} }),则推断类型将为undefined

    const test3 = getStyleNew(theme, 'header', 'fontSize'); // inferred: test3: undefined
    

    不确定这是否是最优雅的解决方案,但extends 子句保证键的类型安全,所以它应该是正确的。

    TypeScript playground

    【讨论】:

      猜你喜欢
      • 2020-02-15
      • 2021-08-08
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      相关资源
      最近更新 更多