什么是使用“as”真正做的这个Typescript显式类型转换?

时间:2018-02-06 14:51:42

标签: javascript typescript

我刚刚阅读了这个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[]真的做了什么,或者如果没有第二种类型声明会没问题呢?

3 个答案:

答案 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)没有声明的函数,使用可分配的对象文字并绕过编译器检查就可以了。在课堂上。