繁体   English   中英

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

[英]error TS2339: Property 'x' does not exist on type 'Y'

我不明白为什么这段代码会产生 TypeScript 错误。 (非原码,有点派生,例子中的废话请无视):

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

function getMainImageUrl(images: Images): string {
  return images.main;
}

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

错误 TS2339:属性“main”在类型“Images”上不存在。

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

return images["main"];

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

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

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

function getMainImageUrl(images: Images): string {
    return images.main;
}

您不能使用点表示法访问索引属性,因为打字稿无法知道对象是否具有该属性。
但是,当您专门定义一个属性时,编译器就会知道它是否存在(或不存在),它是否是可选的以及类型是什么。


编辑

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

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");
}

我已经实现了类似的东西,我发现它非常有用。

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

(Hacky) 解决方法 1

您可以将对象分配给any类型的常量,然后调用“不存在”属性。

const newObj: any = oldObj;
return newObj.someProperty;

您也可以将其转换为any

return (oldObj as any).someProperty;

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


(Hacky) 解决方法 2

如果您无法修改原始类型,您可能会考虑的另一件事是像这样扩展类型

interface NewType extends OldType {
  someProperty: string;
}

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

return (oldObj as NewType).someProperty;

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

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

return json.property[0].index

其中 index 是一个变量。 但它解释了index ,结果是:

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

我不得不使用您的语法找到一种解决方法:

return json.property[0][index]

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

从 TypeScript 2.2 开始,允许使用点表示法访问索引属性。 您不会在示例中收到错误 TS2339。

请参阅TypeScript 2.2 发行说明中带有字符串索引签名的类型的 Dotted 属性

正确的解决方法是在类型定义中添加属性,如@Nitzan Tomer 所述。 但是,如果您想像在 JavaScript 中一样编写代码,您也可以将属性定义为any

arr.filter((item:any) => {
    return item.isSelected == true;
}

我在 Vue 3 上遇到了这个错误。这是因为必须像这样导入defineComponent

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
    name: "HelloWorld",
    props: {
        msg: String,
    },
    created() {
        this.testF();
    },
    methods: {
        testF() {
            console.log("testF");
        },
    },
});
</script>

在这个例子中,帮助我的是将变量变为公共变量:

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

function getMainImageUrl(images: Images): string {
  return images.main;
}

据说不那么hacky的解决方案:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM