你能在类型声明中得到准确的当前索引键吗?

Can you get the exact currently indexed key in types declaration?

我正在尝试创建一个相对简单的类型,该类型将强制对外部级别执行嵌套对象键引用。

为了更清楚地说明问题,这里有一个例子:

const obj = {
  foo: {
     name: 'bar',
     ref: 'foo' // < this should reference the key of the parent
  }
}

这在静态对象类型中显然不是问题,我们只需要检查 'foo',但我试图确保它是动态的,具有泛型类型参数。

我尝试了以下方法:

type InnerObject<K> = {
   name: string,
   ref: K,
}

type OuterObject<T, K extends keyof T> = {
   [key in K]: InnerObject<K>
}

这几乎可以正常工作,对当前键的并集执行类型检查:

问题在于,它还允许将其他对象键传递给 ref 属性,而它显然不应该。

我一直在考虑以某种方式创建第三种泛型并将其传递给 Exclude 实用程序类型,即

type InnerObject<T, K extends keyof T, CurrentKey> = {
   name: string,
   ref: Exclude<CurrentKey, K>
}

但问题是,我想不出一种方法来传递索引对象的当前键,而无需在外部对象上编写显式缩减器/映射函数。

这是可行的,还是在 中根本不可能?


这是 link to the playground 的问题。

如果你有一个类似 Example 的类型想要转换成这个结构,你可以这样做:

type OuterObject<T extends object> = {
    [K in keyof T]: InnerObject<K>
}

我们的想法是 mapping InnerObject<K> 超过 每个 K keyof T

重要的是,这与您所写的不同之处在于,您是在整个联合 keyof T 上操作,而不是在联合中的每个元素上操作。这是 {[X in Y]: F<X>}{[X in Y]: F<Y>} 之间的区别,前者对每个 属性 的计算结果可能不同。

这会产生您正在寻找的行为:

const obj: OuterObject<Example> = {
    foo: {
        name: 'whatever',
        ref: 'foo',
    },
    bar: {
        name: 'baz',
        ref: 'foo' // error!
    }
}

这对你有用吗?

Playground link to code