标题说明了一切-为什么Object.keys(x)
在TypeScript 中不返回类型Array<keyof typeof x>
?就是这样Object.keys
做的,因此对于TypeScript定义文件作者来说,似乎很明显的疏忽是不将返回类型简单地设为keyof T
。
我应该在他们的GitHub存储库上记录错误,还是继续发送PR为其进行修复?
Rya*_*ugh 36
当前的返回类型(string[]
)是有意的。为什么?
考虑这样的某种类型:
interface Point {
x: number;
y: number;
}
Run Code Online (Sandbox Code Playgroud)
您编写如下代码:
function fn(k: keyof Point) {
if (k === "x") {
console.log("X axis");
} else if (k === "y") {
console.log("Y axis");
} else {
throw new Error("This is impossible");
}
}
Run Code Online (Sandbox Code Playgroud)
让我们问一个问题:
在类型良好的程序中,可以通过法律电话
fn
打到错误案例吗?
该所希望的答案是,当然是“否”。但是,这与什么有关Object.keys
呢?
现在考虑其他代码:
interface NamedPoint extends Point {
name: string;
}
const origin: NamedPoint = { name: "origin", x: 0, y: 0 };
Run Code Online (Sandbox Code Playgroud)
请注意,根据TypeScript的类型系统,所有NamedPoint
都有效Point
。
现在让我们再编写一些代码:
function doSomething(pt: Point) {
for (const k of Object.keys(pt)) {
// A valid call iff Object.keys(pt) returns (keyof Point)[]
fn(k);
}
}
// Throws an exception
doSomething(origin);
Run Code Online (Sandbox Code Playgroud)
我们类型良好的程序只是引发了异常!
这里出问题了!通过返回keyof T
的Object.keys
,我们已经违反了这一假设keyof T
形成一个详尽的清单,因为有一个对象的引用并不意味着引用的类型不是的超类型的值的类型。
基本上,(至少)以下四件事之一不能成立:
keyof T
是以下各项的详尽清单: T
Object.keys
退货 keyof T
丢掉点1 keyof
几乎没有用,因为它暗示keyof Point
可能是不等于"x"
或的一些值"y"
。
扔掉点2会完全破坏TypeScript的类型系统。没有选择。
扔掉第3点也会完全破坏TypeScript的类型系统。
丢掉第4点就可以了,这使程序员,您可以考虑所处理的对象是否可能是您所拥有的事物的子类型的别名。
“丢失的功能”,使这个合法的,但并不矛盾是精确的类型,这样可以让你声明一个新种类型的,这是不符合点#2。如果存在此功能,则可能只对声明为precision的 s Object.keys
返回。keyof T
T
Sep*_*eed 15
这是此类问题在谷歌上的热门搜索,因此我想分享一些关于前进的帮助。
这些方法很大程度上取自各个问题页面上的长时间讨论,您可以在其他答案/评论部分找到这些页面的链接。
所以,假设你有一些这样的代码:
const obj = {};
Object.keys(obj).forEach((key) => {
obj[key]; // blatantly safe code that errors
});
Run Code Online (Sandbox Code Playgroud)
以下是一些前进的方法:
如果您不需要键而实际上只需要值,请使用.entries()
or.values()
而不是迭代键。
const obj = {};
Object.values(obj).forEach(value => value);
Object.entries(obj).forEach([key, value] => value);
Run Code Online (Sandbox Code Playgroud)
创建一个辅助函数:
function keysOf<T extends Object>(obj: T): Array<keyof T> {
return Array.from(Object.keys(obj)) as any;
}
const obj = { a: 1; b: 2 };
keysOf(obj).forEach((key) => obj[key]); // type of key is "a" | "b"
Run Code Online (Sandbox Code Playgroud)
重新转换你的类型(这对于不必重写太多代码有很大帮助)
const obj = {};
Object.keys(obj).forEach((_key) => {
const key = _key as keyof typeof obj;
obj[key];
});
Run Code Online (Sandbox Code Playgroud)
其中哪一项最无痛很大程度上取决于您自己的项目。
在您确信正在使用的对象中没有额外属性的情况下,对于解决方法,您可以执行以下操作:
const obj = {a: 1, b: 2}
const objKeys = Object.keys(obj) as Array<keyof typeof obj>
// objKeys has type ("a" | "b")[]
Run Code Online (Sandbox Code Playgroud)
如果您愿意,可以将其提取到函数中:
const getKeys = <T>(obj: T) => Object.keys(obj) as Array<keyof T>
const obj = {a: 1, b: 2}
const objKeys = getKeys(obj)
// objKeys has type ("a" | "b")[]
Run Code Online (Sandbox Code Playgroud)
作为奖励,这是Object.entries
从GitHub 问题中提取的关于为什么这不是默认值的上下文:
type Entries<T> = {
[K in keyof T]: [K, T[K]]
}[keyof T][]
function entries<T>(obj: T): Entries<T> {
return Object.entries(obj) as any;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2410 次 |
最近记录: |