typescript - 如何访问 : K extends keyof T, T[K] 的嵌套类型,例如T[K] ["someSubField"]

标签 typescript typing

我有以下功能:

const fieldDefinitions = {
  a: { id: "14", "default": "none" },
  b: { id: "15", "default": 0 },
  c: { id: "16", "default": 0 },
};

const setFields = <T extends typeof fieldDefinitions, K extends keyof T>(fieldValues: { fieldName: K, value: T[K]["default"] }[]) => {
  //logic to set fields
}

我想以一种只接受与默认值类型相同的字段值的方式键入它。

例如:

setFields([
  { fieldName: "a", value: "somestring" },
  { fieldName: "c", value: 123 },
])
//should work because:
// - default of a is "none" which is a string
// - default of c is 0 which is a number


setFields([
  { fieldName: "a", value: 123 },
  { fieldName: "c", value: "somestring" },
])
//should NOT work because:
// - default of a is "none" which is a string, but a number is given
// - default of c is 0 which is a number, but a string is given

这是我在类型定义中遇到错误的地方:

value: T[K]["default"]

它说:类型“default”不能用于索引类型“T[K]”

所以我的问题是,在这里访问 T[K] 的“默认”属性的类型的正确方法是什么?

这是 TypeScript Playground 中的代码:

最佳答案

如果T扩展typeof fieldDefinitions,这意味着它可以是具有任何其他属性的任何子类型,而这些属性不具有default的对象类型.

T 并未真正使用,您只希望 fieldDefinitions 不是它的子类型,因此您可以执行以下操作:


type FieldDefinitions = typeof fieldDefinitions
/**
 * The field value should be enforced to be the same type as the default value in the definition
 */
const setFields = <K extends keyof FieldDefinitions>(fieldValues: { fieldName: K, value: FieldDefinitions[K]["default"] }[]) => {
  //logic to set fields
}

Playground Link

但是,这不会真正解决您想要解决的问题。它不能确保在数组的元素中,键和值是相关的(将被键入为所有现有键的联合)

这里真正的解决方案是使用映射类型作为参数。这种技术有时称为反向映射类型,将确保 TS 能够遵循数组每个元素内的相关性:

const fieldDefinitions = {
  a: { id: "14", "default": "none" },
  b: { id: "15", "default": 0 },
  c: { id: "16", "default": 0 },
};

type FieldValues<T> = {
    [P in keyof T]: { fieldName: T[P], value: typeof fieldDefinitions[T[P] & FieldDefinitionKeys]['default'] }
}

type FieldDefinitionKeys = keyof typeof fieldDefinitions
const setFields = <T extends [FieldDefinitionKeys] | FieldDefinitionKeys[]>(fieldValues: FieldValues<T>) => {
}



// works
setFields([
  { fieldName: "a", value: "somestring" },
  { fieldName: "c", value: 123 },
])

//does not work
setFields([
  { fieldName: "a", value: 123 },
  { fieldName: "c", value: "somestring" },
])

Playground Link

关于typescript - 如何访问 : K extends keyof T, T[K] 的嵌套类型,例如T[K] ["someSubField"],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73384699/

相关文章:

javascript - 如何使用 Aurelia 和 typescript 获得 karma 覆盖?

binary - 打字时如何表示不同的数字系统?

PHP 混合类型 vs Typescript any

python - 是否有任何内置的 lambda for is notNone in python

python - 禁止使用 python 类型将枚举条目作为函数参数的值

javascript - 以随机顺序运行单元测试有什么意义?

javascript - Typescript -w(watch) 在我的安装中不起作用

Angular Firebase 将时间戳检索为日期

css - TSX 组件中样式标签中 CSS 的语法突出显示

mongodb - 如何在 typescript 中输入 Mongoose ObjectID数组