繁体   English   中英

TypeScript 不安全地使用“任何”类型的表达式错误

[英]TypeScript Unsafe use of expression of type 'any' ERROR

我是 TypeScript 的新手,并将我的场景描述如下:

我有这样的类型:

 type response = {
  totalQuantity: number;
  numberOfCatogory: number
  appleQuantity: number;
  bananaQuantity: number;
  pearQuantity: number;
};

每个单独的水果数量都有验证,在这种情况下是 appleQuantity、bananaQuantity 和 pearQuantity,这意味着我需要从响应中获取每个单独的水果数量。

所以我创建了一个字符串数组,它像这样保存单个属性键:
const individualParameters: string[] = ["appleQuantity", "bananaQuantity", "pearQuantity"]

Function 逻辑如下:

for (const individualParameter of individualParameters) {
    let individualQuantity = response[individualParameter];
    ...
}

但是当我构建时,TSLint 在response[individualParameter]上抛出错误说

Unsafe use of expression of type 'any'

我认为这是因为响应无法识别字符串数组元素的类型?
我是 TypeScript 的新手,很好奇解决这个问题的好方法。

问题出在这一行: const individualParameters:string[] = ["appleQuantity", "bananaQuantity", "pearQuantity"]

根据individualParameters的类型定义,每个元素都是一个string 这意味着即使这个"foo"字符串也可以分配给类型string

因此,typescript 拒绝使用response[individualParameter]因为response是具有严格键的类型,而individualParameter可能是任何字符串。

为了使其工作,您可以使用const assertion

type response = {
  totalQuantity: number;
  numberOfCatogory: number
  appleQuantity: number;
  bananaQuantity: number;
  pearQuantity: number;
};

const individualParameters = ["appleQuantity", "bananaQuantity", "pearQuantity"] as const

declare const response: response;

for (const individualParameter of individualParameters) {
  let individualQuantity = response[individualParameter]; // ok

}

如果您不喜欢as const方法,可以使用额外的 function:

type response = {
  totalQuantity: number;
  numberOfCatogory: number
  appleQuantity: number;
  bananaQuantity: number;
  pearQuantity: number;
};


declare const response: response;

const iterator = <
  Obj extends Record<string, number>,
  Keys extends Array<keyof Obj>
>(record: Obj, keys: Keys) => {
  for (const individualParameter of keys) {
    let individualQuantity = record[individualParameter];
  }
}

iterator(response, ['foo']) // expected error

// works only with literal array
iterator(response, ["appleQuantity", "bananaQuantity", "pearQuantity"]) // ok

操场

Obj - 表示response参数, Keys - 确保第二个数组参数由有效的Obj键组成

PS 根据 TS 约定,类型应该大写。

所以我认为大多数人已经解释了发生了什么,我认为到目前为止我个人最喜欢的答案是船长-yossarian 的答案 他很好地解释了这个问题:

因此,typescript 拒绝使用 response[individualParameter] 因为 response 是具有严格键的类型,而 individualParameter 可能是任何字符串。

但是,可以通过告诉 Typescript 您正在定义一个包含字符串的数组来轻松解决此问题,这些字符串也是您尝试访问的类型的键:

type response = {
  totalQuantity: number;
  numberOfCatogory: number
  appleQuantity: number;
  bananaQuantity: number;
  pearQuantity: number;
};

// this should be your non-null and defined object in reality
let response: response;

// just this one line below was altered
const individualParameters: (keyof response)[] = ["appleQuantity", "bananaQuantity", "pearQuantity"];

for (const individualParameter of individualParameters) {
    let individualQuantity = response[individualParameter];
}

类型(keyof response)[]意味着您将始终拥有一个仅包含response类型键的数组。 在我的示例中,此声明是多余的,因为编译器已经可以推断出您定义的所有属性都是该类型的键,但是当 for 循环位于 function 中时,情况就不同了。 我假设你就是这种情况,否则你不会在第一种情况下问这个问题。

@captain-yossarian 是对的; 根据 TS 约定,类型应该大写。

您需要使您的响应可索引。 更多信息可以在这里找到。

在您的情况下,可以通过使用如下接口来完成:

interface IResponse {
  [key: string]: number;  // <- This line makes your interface indexable
  totalQuantity: number;
  numberOfCatogory: number
  appleQuantity: number;
  bananaQuantity: number;
  pearQuantity: number;
}

现在你只需要确保你的响应实现了 IResponse 接口:

const response: IResponse = {
  totalQuantity: 1,
  numberOfCatogory: 2,
  appleQuantity: 3,
  bananaQuantity: 4,
  pearQuantity: 5
}

在此之后,您可以使用字符串数组来获取单个水果数量,如下所示:

const individualParameters: string[] = ["appleQuantity", "bananaQuantity", "pearQuantity"];

for (let individualParameter of individualParameters) {
    console.log(response[individualParameter]);
}

// Output:
// 3
// 4
// 5

一种简单的方法是您可以选择将类型的键设为字符串变量

type response  = {
    [key: string]: number;
};

但是,如果您真的要修复 key 为 appleQuantity、 bananaQuantity 、blablabla,您可以尝试Mapped Type ,点击此链接了解更多详情

暂无
暂无

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

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