错误TS2339:类型'Y'上不存在属性'x'

hgo*_*ebl 35 typescript

我不明白为什么这段代码会生成TypeScript错误.(这不是原始代码,有点派生,所以请忽略示例中的无意义):

interface Images {
  [key:string]: string;
}

function getMainImageUrl(images: Images): string {
  return images.main;
}
Run Code Online (Sandbox Code Playgroud)

我收到错误(使用TypeScript 1.7.5):

错误TS2339:"图像"类型中不存在属性"main".

当然,写作时我可以摆脱错误:

return images["main"];
Run Code Online (Sandbox Code Playgroud)

我不想使用字符串来访问该属性.我能做什么?

Nit*_*mer 21

如果您希望能够访问,images.main则必须明确定义它:

interface Images {
    main: string;
    [key:string]: string;
}

function getMainImageUrl(images: Images): string {
    return images.main;
}
Run Code Online (Sandbox Code Playgroud)

您无法使用点表示法访问索引属性,因为typescript无法知道对象是否具有该属性.
但是,当您专门定义属性时,编译器会知道它是否存在(无)是否可选以及类型是什么.


编辑

您可以为地图实例创建一个辅助类,例如:

class Map<T> {
    private items: { [key: string]: T };

    public constructor() {
        this.items = Object.create(null);
    }

    public set(key: string, value: T): void {
        this.items[key] = value;
    }

    public get(key: string): T {
        return this.items[key];
    }

    public remove(key: string): T {
        let value = this.get(key);
        delete this.items[key];
        return value;
    }
}

function getMainImageUrl(images: Map<string>): string {
    return images.get("main");
}
Run Code Online (Sandbox Code Playgroud)

我有类似的东西实现,我发现它非常有用.

  • 这种意义上的地图就像一个数组,您可以使用方括号访问元素 (2认同)

Nel*_*elu 12

正确的解决方法是在类型定义中添加属性,如@Nitzan Tomer的答案中所述.如果那不是一个选择:

(Hacky)解决方法1

您可以将对象分配给any类型的常量,然后调用'non-existing'属性.

const newObj: any = oldObj;
return newObj.someProperty;
Run Code Online (Sandbox Code Playgroud)

您也可以将其投射为any:

return (oldObj as any).someProperty;
Run Code Online (Sandbox Code Playgroud)

这无法提供任何类型安全性,这是TypeScript的重点.


(Hacky)解决方法2

您可以考虑的另一件事是,如果您无法修改原始类型,则扩展类型如下:

interface NewType extends OldType {
  someProperty: string;
}
Run Code Online (Sandbox Code Playgroud)

现在您可以将变量转换为此NewType而不是any.仍然不理想,但不太宽松any,给你更多的类型安全.

return (oldObj as NewType).someProperty;
Run Code Online (Sandbox Code Playgroud)


Whe*_*ver 8

正如已经提到的,

Typescript 无法知道该对象是否具有该属性

所以这个错误是合法的。但是,如果我们在访问该属性之前检查该属性是否存在,Typescript 会考虑到这一点并允许点访问:

if ("property" in obj) {
  console.log(`Can access ${obj.property}`)
}

Run Code Online (Sandbox Code Playgroud)

  • 请提供解释。请参阅[如何回答](https://stackoverflow.com/help/how-to-answer)。 (2认同)

Yas*_*che 5

我不是 Typescript 方面的专家,但我认为主要问题是访问数据的方式。看看您如何描述您的Images界面,您可以将任何键定义为字符串。

我认为,当访问属性时,“点”语法 ( images.main) 假设它已经存在。我在没有 Typescript 的情况下遇到了这样的问题,在“vanilla”Javascript 中,我尝试访问数据:

return json.property[0].index

其中索引是一个变量。但它解释了index,导致:

cannot find property "index" of json.property[0]

我必须使用您的语法找到解决方法:

return json.property[0][index]

这可能是您唯一的选择。但是,再次强调,我不是 Typescript 专家,如果有人知道更好的解决方案/解释所发生的情况,请随时纠正我。

  • 这是一个完全不同的问题。 (3认同)
  • 不,这不是问题。属性“main”存在。这不是运行时问题,而是编译时问题。我没有通过变量访问该属性,但“main”实际上是该属性的名称。 (3认同)