【问题标题】:Typescript, parameter's type is circumvented打字稿,参数的类型被规避
【发布时间】:2017-11-03 11:06:24
【问题描述】:

我偶然发现了以下内容

const myObject = new Object();
myObject['test'] = 'hello';

calc(myObject['test']);

function calc(x: number) {
  console.log(x * 10);
}

这是一个非常简单的案例。

我的期望是 TypeScript 至少会在编译时抱怨它找不到具体类型,但 calc 需要一个数字。

相反,TypeScript 根本不会抱怨,并且在控制台中会有 NaN

我在使用 Angular 4 和路由数据时首先注意到了这种行为。

const routes: Routes = [
    {
        path: '**',
        data: [{error: new ApplicationError('http-status-404', '', HttpErrorStatus.NotFound)}],
        component: ApplicationErrorComponent,
        resolve: {
            error: ApplicationErrorResolve
        }
    }
];

@Injectable()
export class ApplicationErrorResolve implements Resolve<ApplicationError> {

   constructor(private applicationErrorHandler: ApplicationErrorHandler) { }

   resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): ApplicationError {

        if (route.data != null && route.data[0]['error'] instanceof ApplicationError) {
            this.applicationErrorHandler.addError(route.data[0]);

            return route.data[0];
        }

        return null;
    }
}

// signature of applicationErrorHandler.addError
addError(error: ApplicationError, navigateToErrorPage: boolean = true) {

}

如代码所示,我的对象ApplicationError 将驻留在route.data[0].error 而不是route.data[0]。 但是 TypeScript 再次没有抱怨,在运行时我只会有完全错误的对象(类型)

我能做些什么(除了手动检查 instanceof 或类似的东西)? 像某种守卫或打字稿开关(如--strictNullCheck)?

来自 c# 背景,这让我非常惊讶(也有点担心)

编辑

感谢 Saravana,第一部分(简单示例)有效。 但是一旦我使用数组,它就会再次失败。即使noImplictAny = true

 const myArray = new Array<any>();
 myArray[0] = { name: 'test'};
 myArray[1] = { name: 1} ;

 // TypeScript doesn't complain 
 this.calc(myArray[0]);

 // TypeScript doesn't complain
 this.calc(myArray[0].ImActuallyNotPresent);

 function calc(x: number) {
     console.log(x * 10);
 }

我不明白。为什么这行得通? 我知道这与any 有关,但为什么myArray 的定义会取代我的方法签名? 这对我来说毫无意义,并且给人一种虚假的安全感。

有没有办法解决这个问题?

【问题讨论】:

  • 我认为那是因为您使用了括号表示法。试试myObject.test = 'hello'; calc(myObject.test); 看看会发生什么。
  • 当使用test 作为属性时它确实有效。但我认为我的类型化方法不应该依赖于我如何提供参数。
  • 括号表示法是 javascript 在运行时确定的一种反射技术。最好声明一个接口并将其类型转换为它。
  • 但我不明白为什么 TypeScript 在编译时不报错?我的方法有一个类型化的参数,我只提供“一些东西”。为什么这甚至行得通?我在 TypeScript 中遗漏了什么吗?
  • @Arikael 如果您想要类型检查,请停止使用any。需要类型检查时始终定义类型。

标签: angular typescript types


【解决方案1】:

您需要在tsconfig.json 中设置"noImplicitAny": true 或将--noImplicitAny 标志传递给编译器以捕获这些问题。

如果您打开了noImplicitAny,编译器将根据calc 检查myObject['test'] 的类型。由于它已关闭,myObject['test'] 的类型被视为any,这会禁用所有类型检查,从而允许将其传递给calc

使用"noImplicitAny": true,您的示例会引发以下错误:

元素隐式具有“任何”类型,因为“对象”类型没有 索引签名。

TypeScript 编译器选项:https://www.typescriptlang.org/docs/handbook/compiler-options.html


当您在示例中执行 const myArray = new Array&lt;any&gt;(); 时,您是在告诉编译器 myArray 可以包含任何内容的数组。编译器唯一要验证的是myArray 是一个数组。数组的内容可以是任何东西。这就是myArray[0].ImActuallyNotPresent 不会抛出任何错误的原因。因为你没有告诉编译器数组的内容。

为确保对数组内容进行类型检查,请提供数组的类型信息:

interface MyArrayContent {
  someString: string;
  someNumber: number
}

const myArray = new Array<MyArrayContent>();
myArray[0] = { someString: 'test', someNumber: 1 };
myArray[1] = { someString: "test2", someNumber: 2};

calc(myArray[0]); // Error
calc(myArray[0].ImActuallyNotPresent); // Error
calc(myArray[0].someString); // Error
calc(myArray[0].someNumber); // No error

function calc(x: number) {
  console.log(x * 10);
}

any 是 TypeScript 绕过所有类型检查并进入完整 JS 模式并忽略所有编译时检查的方法——其中包括验证 calc 是否具有 number 参数。我理解混乱。在像 C# 这样的语言中,即使所有 strings 都是 objects,当方法期望 string 没有强制转换时,您也不能传递 object 类型的变量。但是,如果您将any 视为“在使用此变量时禁用所有类型检查”的同义词,那将更有意义。

any 文档:https://www.typescriptlang.org/docs/handbook/basic-types.html#any

【讨论】:

  • 谢谢,这回答了第一部分(简单的例子)。但是第二个(角度的实际问题)我仍然没有解决。我在问题中添加了另一个示例(在编辑下方),它显示了数组的问题。
  • 再次感谢,我遇到的问题不是我可以使用ImActuallyNotPresent。这是我所期望的,因为any 但我没想到calc 会接受myArray[0]myArray[0].ImActuallyNotPresent,因为就像你说的那样,它可以是任何东西,而不仅仅是一个数字。但我明确告诉calcs 参数x 只接受number。那是我不明白的。当我定义参数必须为number时,为什么我可以提供any作为参数?
  • @Arikael any 是 TypeScript 绕过所有类型检查并进入完整 JS 模式并忽略所有编译时检查的方法——其中包括验证 calc 是否具有 number 参数.我理解混乱。在像 C# 这样的语言中,当方法需要 string 而不进行强制转换时,您不能传递 object 类型的变量。但是,如果您将 any 视为 disable all type checks 的同义词,那就更有意义了。
  • 现在我明白了,也许您可​​以将您的最后一条评论添加到您的答案中,因为 disable all type checks 正是我误解/遗漏的。让我想知道为什么 Angular 团队决定将any 用于路由数据而不是object
猜你喜欢
  • 2018-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-13
  • 2017-11-08
  • 2019-03-20
  • 2022-01-12
相关资源
最近更新 更多