在使用VIEW_PRODUCT类型调用fooBar函数时,TypeScrip编译器没有为配置参数提供准确的建议.虽然当提供了不正确的密钥时,它会正确地检测错误,但它无法强制只存在FooFn接口中定义的一个密钥.在这种情况下,我能得到正确的建议吗?

interface Window {
  fooBar: FooFn
}

interface FooFn {
  (method: 'event', type: 'view_product', config: { view_product_key: any }): void
  (method: 'event', type: 'update_cart', config: { update_cart_key: any }): void
}

window.fooBar('event', 'view_product', {}) // TypeScript incorrectly allows passing an object with more than one key
window.fooBar('event', 'view_product', { update_cart_key: 1 }) // TypeScript correctly flags an error for an incorrect key
window.fooBar('event', 'view_product', { view_product_key: 1 }) // TypeScript correctly allows a valid object with the right key

enter image description here

Playground

推荐答案

你遇到了智能感知自动建议测试的限制,正如在microsoft/TypeScript#51047中所报告的那样.看起来,不同于字符串literal types的参数的重载最终被错误地集中在完成列表中.除非该问题得到解决,否则您需要要么接受这个问题,要么进行重构以避免重载.

实现这一点的一种方法是使用generics而不是重载.您可以编写一个"映射"接口,将您的参数表示为对象 struct .

interface ConfigMap {
  event: {
    view_product: { view_product_key: any };
    update_cart: { update_cart_key: any };
  };
}

对于该类型,您希望FooFn接受键ConfigMap作为其第一个参数,然后深入到该属性,并使下一个参数成为该类型的键,然后最后一个参数应该是该嵌套键的属性值.这可以表示为使用泛型和indexed access types的调用签名:

interface FooFn {
  <K1 extends keyof ConfigMap, K2 extends keyof ConfigMap[K1]>(
    method: K1, type: K2, config: ConfigMap[K1][K2]
  ): void    
}

因此,AFooFn有两个泛型类型参数.method的参数是K1,也就是constrainedConfigMapkeys.type参数的值为K2,它被限制为键ConfigMap[K1](这是位于ConfigMapK1键的属性类型).

然后config的类型是ConfigMap[K1][K2],如果你向下钻取ConfigMapK1属性,然后是ConfigMap[K1]K2属性,那么属性的类型就是ConfigMap[K1][K2].

这在接受和拒绝的呼叫方面表现得更多或相同:

window.fooBar('event', 'view_product', { update_cart_key: 1 }) // error
window.fooBar('event', 'view_product', { view_product_key: 1 }) // okay

但现在,智能感知的范围缩小了,因此您只能看到适当的完成:

window.fooBar('event', 'view_product', {});
              suggestion:               ^ view_product_key 

这是因为当您编写window.fooBar('event', 'view_product', 时,编译器能够将"event"推断为K1,将"view_product"推断为K2,因此config的类型是{view_product_key: any}.在呼叫签名中没有留下update_cart_key的痕迹来阻碍.

Playground link to code

Typescript相关问答推荐

使用前的组件渲染状态更新

有没有办法适当缩小类型?

TypScript如何在 struct 上定义基元类型?

SortKey类型不起作用,尽管它使用的单个类型工作正常<>'

如何缩小变量访问的对象属性范围?

带占位符的模板文字类型何时扩展另一个?

路由链接不会导航到指定router-outlet 的延迟加载模块

TypeScrip-将<;A、B、C和>之一转换为联合A|B|C

根据类型脚本中的泛型属性 Select 类型

如何获取受类型脚本泛型约束的有效输入参数

->;Boolean类型的键不能分配给类型Never

类型实例化过深,可能是无限的&TypeScrip中的TupleUnion错误

是否将Angular *ngFor和*ngIf迁移到新的v17语法?

如何在Next.js和Tailwind.css中更改悬停时的字体 colored颜色

如何避免多个类型参数重复?

递归类型别名的Typescript 使用

仅当类型为联合类型时映射属性类型

可以';t使用t正确地索引对象;联合;索引类型

JSX.Element';不可分配给类型';ReactNode';React功能HOC

如何解决 Angular 中的 ts(18048) 错误