我正在开发一个 TypeScript 项目,其中对象的键可以是一个值,也可以是一个接受参数(其键从对象的键映射而来)的函数。当函数类型值尝试解构对象上不存在的属性时,我想触发警告。这是我所描述的一个简化示例:
type MappedType<T, V> = {
[K in keyof T] : V
}
type MappingFn<T, V> = (param : MappedType<T, V>) => V;
type SelfReferentialType<T, V> = {
[key : string] : T | MappingFn<SelfReferentialType<T, V>, V>
}
const example : SelfReferentialType<number, string> = {
fieldA : 99,
fieldB : ({ fieldA }) => fieldA.toUpperCase(), //works as expected
fieldC : ({ fieldD }) => fieldD.toUpperCase() //fieldD does not exist, so I would like this to trigger a warning
}
为了澄清,函数类型属性将接收的对象将是一个其键与声明该函数的对象相同的对象,但其值的类型不同。在这个简化的示例中,它们将是字符串。这样的对象可能看起来像这样:
{
fieldA : 'ninety-nine',
fieldB : 'a function',
fieldC : 'another function'
}
我不确定我想要的行为是否可能,但如果有人对如何实现它有任何建议,或者解释为什么它不可能,我将非常感激。提前致谢!
最佳答案
您需要一个 generic输入类似 SelfReferentialType<T, U, K>
哪里K
是你的对象拥有的一组键。
type SelfReferentialType<T, U, K extends PropertyKey> =
{ [P in K]: T | ((o: { [P in K]: U }) => U) }
大概您需要手动指定T
和U
但让编译器推断 K
基于您正在使用的对象文字。不幸的是,TypeScript 不允许直接对泛型类型进行类型参数推断,您需要调用辅助泛型函数才能实现这一点。此外,TypeScript 不允许您在推断其余类型参数时指定某些类型参数,如 microsoft/TypeScript#26242 中的要求。 。要么全有,要么全无。标准的解决方法是写一个 curried功能。在你的情况下,它可能看起来像这样:
const selfReferentialType = <T, U>() => <K extends PropertyKey>(
srt: SelfReferentialType<T, U, K>
) => srt;
并像这样使用它:
const example = selfReferentialType<number, string>()({
fieldA: 99,
fieldB: ({ fieldA }) => fieldA.toUpperCase(), // okay
fieldC: ({ fieldD }) => fieldD.toUpperCase() // error
})
// const example: SelfReferentialType<number, string, "fieldA" | "fieldB" | "fieldC">
调用带有类型参数但没有函数参数的函数,然后立即将返回值作为另一个函数调用,有点奇怪,但它的行为如您所愿:example
对象的类型为SelfReferentialType<number, string, "fieldA" | "fieldB" | "fieldC">
,因此编译器知道这些字段不包括 "fieldD"
然后您会得到所需的错误。
关于typescript - 在 TypeScript 中使用递归类型和映射类型触发过多属性警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76850708/