Javascript TypeScript:访问对象上未定义的键时返回的类型错误?
在TypeScript中使用带有可变键的对象时,我注意到了意外的类型 给定以下代码Javascript TypeScript:访问对象上未定义的键时返回的类型错误?,javascript,typescript,types,Javascript,Typescript,Types,在TypeScript中使用带有可变键的对象时,我注意到了意外的类型 给定以下代码 类型MyType={ [x:编号]:编号 } 常数o:MyType={ 0: 1, } 常数a=o[0];//返回类型正确标识为数字 常数b=o[1];//返回类型应该是未定义的,编译器不允许这样做 我注意到,当使用变量键的[x:number]语法定义对象类型时,使用[…]的对象访问类型无法正确检测 VSCode向我显示a和b都有类型number。类型不应该是number | undefined,因为键可能未定
类型MyType={
[x:编号]:编号
}
常数o:MyType={
0: 1,
}
常数a=o[0];//返回类型正确标识为数字
常数b=o[1];//返回类型应该是未定义的,编译器不允许这样做
我注意到,当使用变量键的[x:number]
语法定义对象类型时,使用[…]
的对象访问类型无法正确检测
VSCode向我显示a
和b
都有类型number
。类型不应该是number | undefined
,因为键可能未定义?将a
和b
记录到控制台时,a
是编号
,而b
是未定义的
如果将类型为MyType
的对象传递给函数,并且该函数访问该对象中的键,然后执行如下操作,则问题会变得更严重:
函数乐趣(o:MyType):编号{
返回o[10000]?null//在运行时可以是数字或null
}
没有显示错误。但是当代码运行时,o[10000]
未定义,因此返回值为null
,这不是一个有效的数字。想象一下,使用此返回值执行进一步的计算,这些计算都基于假设是有效数字。这将导致编译器本应检测到的运行时错误(如果我不理解完全错误的内容,我是TS新手)
(这些示例中使用的TypeScript由CreateReact应用程序配置,我没有更改任何设置)
类型不应该改为number | undefined吗?因为键可能未定义
如果你愿意,你可以选择;只需将其定义为:
type MyType = {
[x: number] : number | undefined
}
如果您希望访问可能不存在的随机属性,这可能很有用
但另一方面,以更严格的方式使用对象是相当常见的,这样可以避免访问不存在的属性。例如,如果您编写的代码通常使用Object.keys(o)
或作为。。。在
中,为了决定要访问哪些属性,您已经在做一些工作来确保它的存在,而typescript总是告诉您它可能未定义,这可能会让您感到沮丧
类型不应该改为number | undefined吗?因为键可能未定义
如果你愿意,你可以选择;只需将其定义为:
type MyType = {
[x: number] : number | undefined
}
如果您希望访问可能不存在的随机属性,这可能很有用
但另一方面,以更严格的方式使用对象是相当常见的,这样可以避免访问不存在的属性。例如,如果您编写的代码通常使用
Object.keys(o)
或作为。。。在
中,为了确定要访问哪些属性,您已经在做确保它存在的工作,而且typescript总是告诉您它可能未定义,这可能会让您感到沮丧。您的MyType
定义了一个索引访问器,允许任何数字用作对象的访问器:
type MyType = {
[x: number] : number
}
这意味着,就类型安全而言,任何数字都可以使用索引访问器访问对象,类似于数组
您的对象只定义一个属性,但类型检查器(编译时间)没有查看您的对象,它是在运行时创建的。类型检查器只知道MyType
,任何数字都是有效值,可用于索引类型为或扩展MyType
的任何对象
您必须记住,在运行时,您的对象仍然只是一个常规的旧JavaScript对象,并且一旦编译并运行代码,TypeScript就不再适用
如果要定义具有一定数量属性的类型,则应使用一定数量的属性构造类型,而不是使用索引访问器:
interface MyType {
0: number
}
const o: MyType = { 0: 1 } // valid
const o2: MyType = { 1: 1 } // type checking error
o[0] // valid
o[1] // type checking error
您的
MyType
定义了一个索引访问器,允许任何数字用作对象的访问器:
type MyType = {
[x: number] : number
}
这意味着,就类型安全而言,任何数字都可以使用索引访问器访问对象,类似于数组
您的对象只定义一个属性,但类型检查器(编译时间)没有查看您的对象,它是在运行时创建的。类型检查器只知道MyType
,任何数字都是有效值,可用于索引类型为或扩展MyType
的任何对象
您必须记住,在运行时,您的对象仍然只是一个常规的旧JavaScript对象,并且一旦编译并运行代码,TypeScript就不再适用
如果要定义具有一定数量属性的类型,则应使用一定数量的属性构造类型,而不是使用索引访问器:
interface MyType {
0: number
}
const o: MyType = { 0: 1 } // valid
const o2: MyType = { 1: 1 } // type checking error
o[0] // valid
o[1] // type checking error
如果有人想要对此问题的“官方”答案,请参阅,请求在索引签名值域中自动包含
未定义的
,以及来自TS团队领导的关于为什么他们认为这不是一个好主意的评论(和)(这会被频繁使用,以至于实际上不会提供安全性)谢谢你的链接。我阅读了大多数评论,我仍然认为默认类型应该包括未定义的
。主要原因是您可能忘记自己添加未定义的。此外,您不希望在forEach
或条目中有|未定义的,因为在这种情况下,您知道它不是未定义的。在github问题上,大多数人似乎都同意我的观点。令人遗憾的是,TS团队不想改变这一点,因为这是导致许多运行时错误和类型错误的原因