打字稿,参数的类型被绕过

时间:2017-06-02 06:20:21

标签: angular typescript types

我偶然发现了以下

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的定义会取代我的方法签名? 这对我来说没什么意义,给人一种虚假的安全感。

有没有解决这个问题?

1 个答案:

答案 0 :(得分:0)

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

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

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

  

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

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

当您在示例中执行const myArray = new Array<any>();时,您告诉编译器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#这样的语言中,即使所有object都是string s,当方法期望string没有强制转换时,也无法传递object类型的变量。但是如果你认为any是“在使用这个变量的地方禁用所有类型检查”的同义词,那就更有意义了。

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