我刚刚阅读了这个example Angular test并看到了一些我以前从未见过的语法。
有一个单元测试将变量声明为自定义类型:
let expectedHeroes: Hero[];
然后它设置了该变量的值,但最后使用as Hero[]
,鉴于该变量已经被输入,我认为这是不必要的:
beforeEach(() => {
heroService = TestBed.get(HeroesService);
expectedHeroes = [
{ id: 1, name: 'A' },
{ id: 2, name: 'B' },
] as Hero[]; //<== WHAT IS THIS?
});
SECOND as Hero[]
真的做了什么,或者如果没有第二种类型声明会没问题呢?
答案 0 :(得分:2)
数组是一个rvalue,它的类型是不能推导出来的(数组是什么?),这就是为什么分配失败,因为在分配的两边都需要强类型。
想象一下分配空数组时的情况:
expectedHeroes = [];
TypeScript如何知道数组的类型?无法猜测。您需要明确指定它:
expectedHeroes = [] as Hero[];
expectedHeroes = <Hero[]>[];
现在对象也是如此。如果你这样做:
expectedHeroes = [{"something": 123}];
TypeScript可以从中推断出多个接口。同样,需要显式类型。我个人建议这样做:
expectedHeroes = <Hero[]>[ ... ]
因为它在写内容时使智能感知聪明(并建议你的属性)
那些&#34;演员&#34;除了告诉类型之外什么都不做,他们没有运行时影响
答案 1 :(得分:2)
鉴于上面声明了let expectedHeroes: Hero[]
,如果expectedHeroes
中的对象具有Hero
类定义的所有属性,那么as Hero[]
似乎没有必要。
但是,如果expectedHeroes
中的对象包含Hero
类定义的属性的子集,as Hero[]
可能只是提供测试所需的属性,同时保持编译器满意(在运行时不重要)。
编辑: @ProfessorAllman已注意到Hero
类有一个Clone
方法,这似乎支持我上面写的内容。如果测试人员只测试其他属性,测试者可能不想在测试中模拟该方法。
答案 2 :(得分:1)
如果您的Hero类中没有声明函数,则不需要强制转换,因为编译器会将您的对象文字视为可赋值。只要您不尝试在列表中的任何项目上调用hero.clone()
,您的投射解决方案就会有效。
一些例子:
class Hero {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
let hero: Hero;
// The "right" way to do it
hero = new Hero("1", "Superman");
console.log(hero instanceof Hero); // true
// Not actually a Hero, but compiler will let it slide
// because it's an assignable object. Note that it does
// not convert the object into a Hero, just tells the
// compiler to ignore the fact that it's not.
hero = { id: "2", name: "Batman" };
console.log(hero instanceof Hero); // false
现在,如果我们在课程中添加的不仅仅是属性,那么事情会有所改变。
class Hero {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
clone() {
alert('cloning ' + this.name);
}
}
let hero: Hero;
hero = new Hero("1", "Superman");
hero.clone(); // works!
// This won't work because if the type system thinks
// the object is a Hero, it will allow hero.clone(),
// which does not exist.
hero = { id: "2", name: "Batman" }; // compiler yells!
// Now let's cast it to a Hero, overriding the compiler's
// checks
hero = { id: "2", name: "Batman" }; // compiler is fine w/ it
// But now the compiler can't catch other problems down
// the line.
hero.clone(); // runtime error: clone is not a function!
在非测试代码中,new Hero
是可以让编译器完成工作的方法。对于测试代码,只要您的代码a)不关心它实际上不是该类的实例并且b)没有声明的函数,使用可分配的对象文字并绕过编译器检查就可以了。在课堂上。