在括号表示法中使用显式类型声明时,如何使用noImplicitAny:false强制TypeScript中的错误?

时间:2019-11-07 18:16:56

标签: typescript

因此,假设您正在使用生产代码库进行工作,该生产代码库是用打字稿完成的,但是它很旧并且有很多隐式any-类似object[key]之类的东西。您可能决定关闭noImplicitAny标志,以免出现大量的编译错误。

但是,当您向项目中添加新代码时,希望在使用方括号表示法时有更好的安全性。我认为您应该可以简单地使用Type Assertion来执行此操作,但是我看到的是它仍然隐式地将文字推断为any(除非字符串靠近键,更多内容在下面...) 。对我来说,这似乎是个错误,但如果有人能在我打开问题之前先解释一下我做错了什么或不理解,就会对此感兴趣。

假设您有一个对象文字,如:

let someObj = {
  "key1": "value1",
  "key2": "value2"
};

您尝试像这样访问它:

let value = someObj['not a valid key'];

如果noImplicitAny标志处于关闭状态,则字符串文字将隐式为any,并且不会对键进行任何检查-启用该标志后,您将准确地得到预期的错误。

因此,您认为关闭标记后,仍然可以这样做以使新代码获得安全性:

let value = someObj['not a valid key' as keyof typeof someObj];

但是上面没有产生任何错误,如果再打开该标志,它还会说:“值隐式具有任何类型,等等...”。那么,当我明确断言它应该是什么时,为什么TypeScript仍会隐式将其转换为any

如果使用变量,它会按预期工作,那么为什么不使用Type Assertion?

let key: keyof typeof someObj = 'not valid key'; // Compile error just like you'd expect.

另一个注意事项-如果您尝试使用其他类型(非字符串)的类型声明,则会导致类似"Conversion of type 'number' to type '"key1" | "key2"' may be a mistake..."的错误-因此它清楚地知道应该传递什么,但似乎不知道该传递什么尊重{我认为)keyof T应该如何保护无效密钥。

2 个答案:

答案 0 :(得分:1)

  

如果noImplicitAny标志处于关闭状态,则字符串文字将隐式为any,并且不会对键进行任何检查

给出noImplicitAny: true和赋值

let value = someObj['not a valid key'];

,TS查找由value得到的类型的显式密钥或合适的索引签名。由于类型没有属性'not a valid key',也没有声明的索引签名,因此属性值将隐式变为any,这违反了noImplicitAny。如果没有此配置选项,则隐式any可以。

  

如果使用变量,它会按预期工作,那么为什么不使用Type Assertion?

因为type assertionsassignments的编译器检查略有不同。对于类似

的作业
let key: keyof typeof someObj = 'not valid key'; // Compile error just like you'd expect.

,一种类型兼容性规则是(S = 'not valid key'T = 'key1'|'key2'):

  

S可以分配给类型T [如果] T是联合类型,而S可以分配给T的至少一个组成类型。

'not valid key'不可同时分配给'key1''key2',因此无法编译。对于type assertions,规则有点different

  

在形式为 e的类型断言表达式中,要求e的结果类型可分配给T,或将T分配给widened形式e的结果类型,否则发生编译时错误。结果的类型为T。

     

类型断言在两个方向上检查分配兼容性。因此,类型断言允许进行可能正确但未知的正确类型转换。

对于type compatibility of unions,如果一个联合的任何给定组成部分与另一种类型兼容,也就足够了(是的,有时候那些“金块”信息深深地散布在github问题中,而不仅是在核心文档)。因此,在分配(T = 'key1'|'key2'e = 'not a valid key'

let value = someObj['not a valid key' as keyof typeof someObj];

'key1''key2'都可以分配给'not a valid key'的加宽形式(= string),我们很高兴-没有编译错误!

希望,您仍处于清醒状态,情况有所澄清。

答案 1 :(得分:0)

在此示例中,“ as”的作用是断言“无效的密钥”实际上是“ key1”。 'key2'。可以,因为您可以断言类型是相似类型,子类型还是超类型。将字符串声明为数字不起作用,因为它们不相关。

let value = someObj['not a valid key' as keyof typeof someObj];

as用于类型声明,您将强制类型检查器假设某些内容,如果您将一个字符串声明为另一个字符串,则它基本上与赋值相同。

回到第一件事...

let value = someObj['not a valid key'];

想象一下这种情况:

let obj = {
  key1: 'hi',
  key2: 'hello'
};
let key = 'key1';
let f = () => {
  key = 'key2';
};
f();
obj[key]; // type any
obj[<keyof typeof obj>key]; // this is a workaround

此处key是通过编程设置的,无论您的noImpicitAny标志是什么,TypeScript都无法推断类型,但是解决方法告诉TypeScript基本信任您。

要使类型检查器确切地知道您要使用点表示法做什么,则不能以编程方式设置键。 (我知道您的问题是如何不必这样做)

let value = someObj.key3;

现在someObj.key3不存在,它是未定义的,无论'noImpicitAny'标志如何,类型检查器都将给出错误。