typescript - 推断 Typescript 中深度嵌套对象的非叶节点类型

标签 typescript

我一直在玩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]'.

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

Playground link

最佳答案

实现此目的的一种方法是将样式记录分配给具有 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

关于typescript - 推断 Typescript 中深度嵌套对象的非叶节点类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66806684/

相关文章:

Diff 类型中使用的 TypeScript 交集类型

javascript - Angular 5 从服务到组件到模板的数据获取数组问题

typescript - 我们如何获取对象的键?

css - Sass 错误 : no mixin named roboto-family Backtrace: src/pages/forms/forms. scss:5

javascript - 类型 '() => void' 不可分配给类型 'string'

javascript - 部分化模板的行为不符合预期

node.js - Node Docker 构建和生产容器最佳实践

javascript - 如何使用 Material ui 自动完成功能进行搜索?

typescript - 没有第三方库的类型安全错误处理

带选择的 Angular Material 表 - 主切换应首先取消选择