typescript - 如何匹配 typescript 中的嵌套键

标签 typescript

我创建了一个简单的 nameOf与 typescript 一起使用的助手。

function nameOf<T>(name: Extract<keyof T, string>) {
  return name;
}

在函数需要表示属性键的字符串但未正确键入的地方,我可以这样使用它:expectsKey(nameOf<MyObject>("someMyObjectProperty")) .这意味着即使我不控制 expectsKey(key: string)我可以对传递给它的字符串进行一些类型检查。这样,如果 MyObject 上的属性重命名,nameOf()调用将显示正常函数在执行之前不会检测到的错误。

是否可以将其扩展到嵌套元素?

即,一些方法可以对 nameOf<MyComplexObject>('someProperty[2].someInnerProperty') 进行类型检查确保它匹配 MyComplexObject 类型的结构?

最佳答案

直接?不可以。您不能创建串联属性以在 TS 中创建新字符串,而这是此功能所必需的。

但是,您可以使用映射类型获得类似的功能。

interface MyObject {
  prop: {
    arr?: { inner: boolean }[]
    other: string
    method(): void
  }
}

// Creates [A, ...B] if B is an array, otherwise never
type Join<A, B> = B extends any[]
  ? ((a: A, ...b: B) => any) extends ((...args: infer U) => any) ? U : never
  : never

// Creates a union of tuples descending into an object.
type NamesOf<T> = { 
  [K in keyof T]: [K] | Join<K, NamesOf<NonNullable<T[K]>>>
}[keyof T]

// ok
const keys: NamesOf<MyObject> = ['prop']
const keys2: NamesOf<MyObject> = ['prop', 'arr', 1, 'inner']

// error, as expected
const keys3: NamesOf<MyObject> = [] // Need at least one prop
const keys4: NamesOf<MyObject> = ['other'] // Wrong level!
// Technically this maybe should be allowed...
const keys5: NamesOf<MyObject> = ['prop', 'other', 'toString']

您不能在 nameOf 函数中直接使用它。这是一个错误,因为类型实例化将被检测为可能是无限的。

declare function nameOf<T>(path: NamesOf<T>): string

但是,如果您让 TypeScript 推迟其解析直到您实际使用该函数,则可以使用 NamesOf。您可以很容易地做到这一点,方法是将其作为通用默认值包含在内,或者将参数类型包装在条件中(这提供了在类型为原始类型时防止使用 nameOf 的额外好处)

interface MyObject {
  prop: {
    arr?: { inner: boolean }[]
    other: string
    method(): void
  },
  prop2: {
    something: number
  }
}

// Creates [A, ...B] if B is an array, otherwise never
type Join<A, B> = B extends any[]
  ? ((a: A, ...b: B) => any) extends ((...args: infer U) => any) ? U : never
  : never

// Creates a union of tuples descending into an object.
type NamesOf<T> = { 
  [K in keyof T]: [K] | Join<K, NamesOf<NonNullable<T[K]>>>
}[keyof T]

declare function nameOf<T>(path: T extends object ? NamesOf<T> : never): string

const a = nameOf<MyObject>(['prop', 'other']) // Ok
const c = nameOf<MyObject>(['prop', 'arr', 3, 'inner']) // Ok
const b = nameOf<MyObject>(['prop', 'something']) // Error, should be prop2

如果你走另一条路线并将路径包含在通用约束中,请确保将路径标记为默认路径(这样你在使用函数时不必指定它)和扩展 NameOf<T> (这样 nameOf 的用户就不能对 key 撒谎)

declare function nameOf<T, P extends NamesOf<T> = NamesOf<T>>(path: P): string

关于typescript - 如何匹配 typescript 中的嵌套键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56605358/

相关文章:

typescript - 使用类型作为具有约束的泛型的别名

javascript - TypeScript:具有已知键的对象上的 Object.keys() 类型过于通用

javascript - 农业网格 vue.js : How to access to the parent grid method of a renderer in typescript?

javascript - 'let 和 'var' 在 Typescript 中是一样的吗?

typescript - 如何在同一命名空间中的多个文件上合并 typescript 接口(interface)

reactjs - 使用带有 Typescript 的样式化组件,prop 不存在?

typescript - VSC @TypeScript 可观察到的错误

javascript - TailwindCSS 深色模式在 Nuxt.js 中不起作用

javascript - 如何清除 Jest 模拟实现以进行下一步测试?

angular - 当变量访问 const 在 Angular/TypeScript 中更新时,const 值发生变化