为什么';t Object.keys返回TypeScript中类型的键?

为什么';t Object.keys返回TypeScript中类型的键?,typescript,Typescript,标题说明了一切-为什么TypeScript中的Object.key(x)不返回类型数组?这就是Object.keys所做的,因此,TypeScript定义文件作者显然疏忽了,没有将返回类型简单地设置为keyof T 我应该在他们的GitHub repo上记录一个bug,还是直接发送一个PR来为他们修复它?当前的返回类型(string[])是故意的。为什么? 考虑以下类型: interface Point { x: number; y: number; } function fn

标题说明了一切-为什么TypeScript中的
Object.key(x)
不返回类型
数组
?这就是
Object.keys
所做的,因此,TypeScript定义文件作者显然疏忽了,没有将返回类型简单地设置为
keyof T

我应该在他们的GitHub repo上记录一个bug,还是直接发送一个PR来为他们修复它?

当前的返回类型(
string[]
)是故意的。为什么?

考虑以下类型:

interface Point {
    x: number;
    y: number;
}
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");
    }
}
您可以编写如下代码:

interface Point {
    x: number;
    y: number;
}
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");
    }
}
让我们问一个问题:

在一个类型良好的程序中,对
fn
的合法调用是否能够命中错误案例?

当然,理想的答案是“不”。但是这与
对象.键有什么关系呢

现在考虑另一个代码:

请注意,根据TypeScript的类型系统,所有
NamedPoint
s都是有效的
Point
s

现在,让我们再编写一些代码:

我们类型良好的程序刚刚抛出了一个异常

这里出了点问题! 通过从
Object.keys
返回
keyof T
,我们违反了
keyof T
形成一个详尽列表的假设,因为引用对象并不意味着引用类型不是值类型的超类型

基本上,(至少)以下四件事之一不可能是真的:

  • keyof T
    T
  • 具有附加属性的类型始终是其基类型的子类型
  • 通过超类型引用别名子类型值是合法的
  • Object.keys
    返回
    keyof T
  • 扔掉点1使得
    keyof
    几乎毫无用处,因为它意味着
    keyof点
    可能是一些不是
    “x”
    “y”
    的值

    丢弃第2点会完全破坏TypeScript的类型系统。没有选择

    扔掉第3点也会完全破坏TypeScript的类型系统

    抛开第4点很好,它会让程序员思考您正在处理的对象是否可能是您认为您拥有的事物的子类型的别名

    使此合法但不矛盾的“缺失特性”是,它允许您声明一种不受第2点约束的新类型。如果存在此功能,则可能只对声明为精确的
    T
    s使用
    Object.keys
    返回
    keyof T


    补遗:当然是泛型? 注释者暗示,如果参数是泛型值,则
    Object.keys
    可以安全地返回
    keyof T
    。这仍然是错误的。考虑:

    class Holder<T> {
        value: T;
        constructor(arg: T) {
            this.value = arg;
        }
    
        getKeys(): (keyof T)[] {
            // Proposed: This should be OK
            return Object.keys(this.value);
        }
    }
    const MyPoint = { name: "origin", x: 0, y: 0 };
    const h = new Holder<{ x: number, y: number }>(MyPoint);
    // Value 'name' inhabits variable of type 'x' | 'y'
    const v: "x" | "y" = (h.getKeys())[0];
    
    类持有者{
    值:T;
    构造函数(arg:T){
    this.value=arg;
    }
    getKeys():(keyof T)[]{
    //提议:这应该可以
    返回Object.keys(此.value);
    }
    }
    常量MyPoint={name:“原点”,x:0,y:0};
    常数h=新的持有人(MyPoint);
    //值“name”驻留在类型为“x”|“y”的变量中
    常数v:“x”|“y”=(h.getKeys())[0];
    
    或者这个示例,它甚至不需要任何显式类型参数:

    function getKey<T>(x: T, y: T): keyof T {
        // Proposed: This should be OK
        return Object.keys(x)[0];
    }
    const obj1 = { name: "", x: 0, y: 0 };
    const obj2 = { x: 0, y: 0 };
    // Value "name" inhabits variable with type "x" | "y"
    const s: "x" | "y" = getKey(obj1, obj2);
    
    函数getKey(x:T,y:T):keyof T{ //提议:这应该可以 返回对象。键(x)[0]; } 常量obj1={name:,x:0,y:0}; 常量obj2={x:0,y:0}; //值“name”驻留在类型为“x”|“y”的变量中 常数s:“x”|“y”=getKey(obj1,obj2);
    当前返回类型(
    string[]
    )是故意的。为什么?

    考虑以下类型:

    interface Point {
        x: number;
        y: number;
    }
    
    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");
        }
    }
    
    您可以编写如下代码:

    interface Point {
        x: number;
        y: number;
    }
    
    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");
        }
    }
    
    让我们问一个问题:

    在一个类型良好的程序中,对
    fn
    的合法调用是否能够命中错误案例?

    当然,理想的答案是“不”。但是这与
    对象.键有什么关系呢

    现在考虑另一个代码:

    请注意,根据TypeScript的类型系统,所有
    NamedPoint
    s都是有效的
    Point
    s

    现在,让我们再编写一些代码:

    我们类型良好的程序刚刚抛出了一个异常

    这里出了点问题! 通过从
    Object.keys
    返回
    keyof T
    ,我们违反了
    keyof T
    形成一个详尽列表的假设,因为引用对象并不意味着引用类型不是值类型的超类型

    基本上,(至少)以下四件事之一不可能是真的:

  • keyof T
    T
  • 具有附加属性的类型始终是其基类型的子类型
  • 通过超类型引用别名子类型值是合法的
  • Object.keys
    返回
    keyof T
  • 扔掉点1使得
    keyof
    几乎毫无用处,因为它意味着
    keyof点
    可能是一些不是
    “x”
    “y”
    的值

    丢弃第2点会完全破坏TypeScript的类型系统。没有选择

    扔掉第3点也会完全破坏TypeScript的类型系统

    抛开第4点很好,它会让程序员思考您正在处理的对象是否可能是您认为您拥有的事物的子类型的别名

    使此合法但不矛盾的“缺失特性”是,它允许您声明一种不受第2点约束的新类型。如果存在此功能,则可能只对声明为精确的
    T
    s使用
    Object.keys
    返回
    keyof T


    补遗:当然是泛型? 评论员暗示,如果