我正在做一个TypeScrip项目,其中对象的键可以是一个值,也可以是一个接受其键从对象的键映射的参数的函数.当函数类型值试图 destruct 对象上不存在的属性时,我希望触发警告.下面是我所描述的一个简化的例子:

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'
}

我甚至不确定我想要的行为是否可能,但如果有人对如何实现它有任何建议,或者对为什么不可能有任何解释,我将非常感激.提前谢谢!

推荐答案

您需要一个类似SelfReferentialType<T, U, K>generic类型,其中K是对象拥有的一组关键点.

type SelfReferentialType<T, U, K extends PropertyKey> =
    { [P in K]: T | ((o: { [P in K]: U }) => U) }

您可能希望手动指定TU,但让编译器infer K基于您正在使用的对象文字.遗憾的是,类型脚本不允许直接对泛型类型进行类型参数推断,需要调用帮助器泛型function才能实现这一点.此外,TypeScrip不允许您在推断其余类型参数时指定某些类型参数,正如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相关问答推荐

使Typescribe强制所有对象具有相同的 struct ,从两个选项

react 路由6操作未订阅从react 挂钩表单提交+也不使用RTK查询Mutations

在映射类型中用作索引时,TypeScrip泛型类型参数无法正常工作

如何在TypeScript中将一个元组映射(转换)到另一个元组?

如何表示多层深度的泛型类型数组?

了解类型规则中的关键字

如何将泛型对象作为返回类型添加到类型脚本中

记录键的泛型类型

CDK从可选的Lambda角色属性承担角色/复合主体中没有非空断言

如何创建一家Reduxstore ?

TypeScrip:从对象中提取和处理特定类型的键

为什么TypeScrip不能解析对象析构中的赋值?

如何将类似数组的对象(字符串::匹配结果)转换为类型脚本中的数组?

带有';的类型脚本嵌套对象可选属性错误满足';

导航链接不触发自定义挂钩

什么';是并类型A|B的点,其中B是A的子类?

为什么类方法参数可以比接口参数窄

带有过滤键的 Typescript 映射类型

使用受保护的路由和入门来响应路由

为什么 typescript 在对象合并期间无法判断无效键?