当您定义像type X = { }这样的类型时,它将具有隐式索引签名,因此它可以作为具有索引签名的泛型参数传递,而相同的interface则没有(这实际上是我发现的行为上的唯一差异,正如我继续说的那样……)

Playground

type A = {
  a: string
}

interface B {
  b: string
}

type Constraint<T extends Record<string, unknown>> = true;

type test1 = Constraint<A>
type test2 = Constraint<B> // Error, as expected, since it does not have an index signature

不过,A的隐式索引签名是什么?为什么它的行为与显式索引签名不同?

type A = {
  a: string
}

interface C {
  [x: string]: string
  c: string
}

let a: A = { };
let c: C = { };

a.x = ''; // Error
c.x = ''; // Ok, only an explicitly defined index signature behaves like one

我不明白,如果这个隐式签名的行为不像一个隐式签名,那么它有什么意义?它是否像上面的例子一样实现为传递泛型约束的黑客?在这种情况下,它对类型判断有实际影响吗?

推荐答案

microsoft/TypeScript#7029中实现的Implicit index signatures被引入以修复microsoft/TypeScript#6041并使object literals能够被分配给index signatures. 也就是说,正在处理的问题是assignability个问题之一.


在TypeScrip 2.0之前,如果您try 将object literal赋给一个变量,然后try 将该变量赋给具有索引签名的类型,则总是失败:

function yell(dict: { [k: string]: string }) {
    for (const k in dict) {
        console.log(k + ": " + dict[k].toUpperCase() + "!!!")
    }
}

let x = { a: "hello", b: "goodbye" };
//  ^? let x: {a: string, b: string}

// TS 1.8 and earlier:
yell(x); // error!
//   ~ <-- {a: string, b: string} has no index signature

This was annoying and confusing, as described at Why can't I indirectly return an object literal to satisfy an index signature return type in TypeScript?. And so we now have implicit index signatures, so that such assignments are allowed:

// TS 2.0 and later:
yell(x); // okay

请注意,这并不意味着您可以使用任何键实际索引到对象文字类型中.这只是为了可分配性.


请注意,最初的错误有一个看似合理的原因.类型脚本中的对象类型不是密封的或精确的(请参见microsoft/TypeScript#12936),这意味着类型{a: string, b: string}的值可能具有类型脚本未知的额外属性,并且这些属性可能与索引签名不匹配:

let y = { a: "hello", b: "goodbye", c: 12345 };
x = y; // allowed!
yell(x); // allowed due to implicit index signature, but runtime error!

因此,隐式索引签名在技术上是不安全的. 但它们实在太方便了,让人舍不得放弃,而另一种 Select 又太不方便了.

Playground link to code

Typescript相关问答推荐

调用另一个函数的函数的Typescript类型,参数相同

React-Native运行方法通过监听另一个状态来更新一个状态

Angular 17 -如何在for循环内创建一些加载?

带有微前端的动态React路由问题

类型断言添加到类型而不是替换

无法将select选项的值设置为ngFor循环中的第一个元素

Angular material 无法显示通过API获取的数据

跟踪深度路径时按条件提取嵌套类型

我可以使用typeof来强制执行某些字符串吗

基于未定义属性的条件属性

从类型脚本中元组的尾部获取第n个类型

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

如何在try 运行独立的文字脚本Angular 项目时修复Visual Studio中的MODULE_NOT_FOUND

KeyOf关键字在特定示例中是如何工作的

必需的输入()参数仍然发出&没有初始值设定项&q;错误

更漂亮的格式数组<;T>;到T[]

如何使用IsEqual创建断言类型相等的实用程序

Vite+Chrome扩展 list v3-;不能在模块外使用import语句;对于inpage脚本

Typescript循环函数引用

如何创建允许使用带有联合类型参数的Array.from()的TS函数?