typescript - 在 TypeScript 中使用递归类型和映射类型触发过多属性警告

标签 typescript typescript-typings typescript-generics

我正在开发一个 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) }

大概您需要手动指定TU但让编译器推断 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"然后您会得到所需的错误。

Playground link to code

关于typescript - 在 TypeScript 中使用递归类型和映射类型触发过多属性警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76850708/

相关文章:

typescript - 打字中的环境依赖性和常规依赖性之间有什么区别

typescript - 如何使用具有动态参数计数的方法输入动态对象

typescript - 组合类型保护签名

compiler-construction - 在 typescript 中是否可以让函数返回扩展它的类的类型

typescript - 在 typescript 2.0 中,如何为 @types npm 命名空间(DefinitelyTyped 存储库)中不可用的模块提供单个声明文件?

通用的 typescript 两层联合类型推断

typescript - 如何查看TypeScript如何计算类型?

typescript 模板文字类型强制结构

javascript - Angular 4 : Subscribing to Observable

javascript - 改变 Angular 指令添加的 CSS?