Javascript 这个Typescript显式类型转换使用的是什么;作为「;真的吗?

Javascript 这个Typescript显式类型转换使用的是什么;作为「;真的吗?,javascript,typescript,Javascript,Typescript,我正在通读这篇文章,看到了一些以前从未见过的语法 有一个将变量声明为自定义类型的单元测试: 让我们期待英雄:英雄[] 然后它设置该变量的值,但最后使用作为Hero[],考虑到该变量已经键入,我认为这是不必要的: beforeEach(() => { heroService = TestBed.get(HeroesService); expectedHeroes = [ { id: 1, name: 'A' }, { id: 2, name: 'B' }, ]

我正在通读这篇文章,看到了一些以前从未见过的语法

有一个将变量声明为自定义类型的单元测试:

让我们期待英雄:英雄[]

然后它设置该变量的值,但最后使用
作为Hero[]
,考虑到该变量已经键入,我认为这是不必要的:

beforeEach(() => {
  heroService = TestBed.get(HeroesService);
  expectedHeroes = [
    { id: 1, name: 'A' },
    { id: 2, name: 'B' },
   ] as Hero[]; //<== WHAT IS THIS?
});
beforeach(()=>{
heroService=TestBed.get(heroEService);
预期英雄=[
{id:1,名称:'A'},
{id:2,名称:'B'},

]由于Hero[];//数组是一个不能推断其类型的右值(what数组?),这就是为什么赋值失败的原因,因为赋值的两边都需要强类型

想象一下分配空数组时的情况:

expectedHeroes = [];
TypeScript如何知道数组的类型?无法猜测。您需要显式指定它:

expectedHeroes = [] as Hero[];
expectedHeroes = <Hero[]>[];
TypeScript可以从中推断出多个接口。同样,需要显式类型。我个人建议这样做:

expectedHeroes = <Hero[]>[ ... ]
expectedHeroes=[…]
因为在编写内容时,intellisense会对类型进行智能化处理(并向您建议属性)


这些“强制转换”除了告诉类型之外什么也不做,它们没有运行时影响

数组是一个不能推断类型的右值(什么数组?),这就是为什么赋值失败的原因,因为在赋值的两侧都需要强类型

想象一下分配空数组时的情况:

expectedHeroes = [];
TypeScript如何知道数组的类型?无法猜测。您需要显式指定它:

expectedHeroes = [] as Hero[];
expectedHeroes = <Hero[]>[];
TypeScript可以从中推断出多个接口。同样,需要显式类型。我个人建议这样做:

expectedHeroes = <Hero[]>[ ... ]
expectedHeroes=[…]
因为在编写内容时,intellisense会对类型进行智能化处理(并向您建议属性)


这些“强制转换”除了告诉类型之外什么也不做,它们没有运行时影响

鉴于上面声明了
让expectedHeroes:Hero[]
,如果
expectedHeroes
中的对象具有
Hero
类定义的所有属性,那么
作为Hero[]
在这里似乎没有必要

但是,如果
expectedHeroes
中的对象包含
Hero
类定义的属性子集,
as Hero[]
可以只提供测试所需的属性,同时让编译器满意(在运行时这无关紧要)


编辑:@ProfessorAllman注意到
Hero
类有一个
Clone
方法,它似乎支持我上面写的内容。如果测试人员只测试其他属性,那么他们可能不想在测试中模仿该方法。

考虑到
让ExpectedHero:Hero[]
是在上面声明的,如果
expectedHeroes
中的对象具有
Hero
类定义的所有属性,那么
作为Hero[]
在这里似乎是不必要的

但是,如果
expectedHeroes
中的对象包含
Hero
类定义的属性子集,
as Hero[]
可以只提供测试所需的属性,同时让编译器满意(在运行时这无关紧要)


编辑:@ProfessorAllman注意到
Hero
类有一个
Clone
方法,它似乎支持我上面写的内容。如果测试人员只测试其他属性,那么他们可能不想在测试中模仿该方法。

如果您的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" } as Hero; // 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)该类上没有声明函数。

如果您的Hero类中没有声明函数,则不需要强制转换,因为编译器会将您的对象文字视为可赋值。只要您不尝试调用
Hero,强制转换解决方案就可以工作。在列表中的任何项目上克隆()

一些例子:

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" } as Hero; // 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)类上没有声明函数。

我还要强调在它没有运行时行为时,一个常见的误解是,对类进行强制转换会生成该类的实例,而该实例不是case@ivan:我意识到了键入的价值,我只是想知道,如果有的话,在声明中键入
let expectedheros:Hero[]
和实例化
expectedheros=[…]作为Hero[]有什么目的
。定义是
让expectedHeroes:Hero[];
,因此,当您为其分配一个普通Jane对象数组时,类型就会被推断出来,并且所有类型检查/智能感知都已经发生,而不需要
作为
。我的直觉告诉我,这是为了自文档化代码,并让程序员明白它是什么类型,而不必返回到声明它的位置。@redocoter13 in在这种情况下,数组是一个右值,编译器无法推断它的类型(什么数组?),这就是为什么赋值失败,因为强类型是exp