当使用Object.keys(obj)
时,返回值是string[]
,而我想要的是(keyof obj)[]
。
const v = {
a: 1,
b: 2
}
Object.keys(v).reduce((accumulator, current) => {
accumulator.push(v[current]);
return accumulator;
}, []);
我有错误:
元素隐式具有“any”类型,因为类型“{ a:编号; b:编号;“}"没有索引签名。
使用strict: true
的TypeScript 3.1。Playground:在这里,请选中Options
中的所有复选框以激活strict: true
。
9条答案
按热度按时间xdnvmnnf1#
Object.keys
会传回string[]
。这是根据此issue中所述的设计这是有意的。TS中的类型是开放式的。所以keysof可能会少于你在运行时得到的所有属性。
有几种解决方案,最简单的一种是只使用一个类型Assert:
您也可以在
Object
中建立keys
的别名,以传回您想要的类型:oknwwptz2#
基于Titian Cernicova-Dragomir的回答和评论
只有当你知道你的对象没有额外的属性时,才使用类型Assert(这是对象文字的情况,而不是对象参数)。
显式Assert
隐藏的声明
使用
getKeys
代替Object.keys
。getKeys
是Object.keys
的引用,但返回值是按字面键入的。讨论
TypeScript的核心原则之一是类型检查关注值所具有的形状。(reference)
x
可以被称为SimpleObject
,因为它有它的形状,这意味着当我们看到SimpleObject
时,我们知道它有属性a
和b
,但它可能还有其他属性。让我们看看如果默认情况下我们按照OP“字面上”的要求键入Object.keys会发生什么:
我们会得到
typeof k
是"a"|"b"
。当迭代时,实际值是a
,b
,c
。Typescript通过将k作为字符串键入来防止这样的错误。类型Assert正好适用于这种情况-当程序员有额外的知识时。如果你知道
obj
没有额外的属性,你可以使用文字类型Assert。ars1skjm3#
(作者:辛德雷胡斯)
1.使用它:
就这样了
下面是我在知道
ts-extras
之前做的另一个例子:第一次
这将返回
['a']
类型的数组4szc88ey4#
请参阅https://github.com/microsoft/TypeScript/issues/20503。
将保留密钥类型而不是
string[]
os8fio9y5#
我完全不同意Typescript团队的决定。
按照他们的逻辑,
Object.values
应该总是返回any,因为我们可以在运行时添加更多的属性...我认为正确的方法是创建带有可选属性的接口,并在运行时设置(或不设置)这些属性...
因此,我只是在本地覆盖了
ObjectConstructor
接口,添加了一个声明文件(也称为:whatever.d.ts)添加到我的项目中,并包含以下内容:注:
Object.keys/Object.entries的基本类型(object)将返回never[]和[never,never][],而不是正常的string[]和[string,any][]。如果有人知道答案,请在评论中告诉我,我将编辑我的答案
所以,小心使用这个......
q1qsirdb6#
您可以使用Extract实用程序类型使您的参数仅符合
obj
中的keys
,这些obj
是字符串(因此,在编码时忽略任何数字/符号)。尽管如此,大多数开发人员可能会认为使用数字作为键是一个糟糕的设计决策/需要修复的bug。
mdfafbf17#
下面是我用类型安全的方式复制对象的一种模式。它使用字符串收缩,这样编译器就可以推断出键实际上是类型。这是用类演示的,但也适用于接口之间或相同形状的匿名类型。
它有点冗长,但可以说比公认的答案更直接。如果你必须在多个地方进行复制操作,它确实保存了打字。
请注意,如果类型不匹配,* 将 * 抛出一个错误,这是您希望的,但 * 不会 * 抛出一个错误,如果在
thingNum
中有丢失的字段。运动场连接
y53ybaqx8#
下面是一个更精确的效用函数:
说明:
keyof T
扩展了string | number | symbol
,但是Object.keys
省略了symbol
键,并以字符串形式返回number
键。我们可以使用模板文字${U}
将数字键转换为字符串。使用此
keys
实用程序:cwdobuhd9#
作为一种可能的解决方案,可以使用
for..in
迭代对象:而这,正如你所说,不会工作: