Angular Typescript Reflect.getMetadata设计:类型返回对象,而不是没有角度测试台的日期
首先,我想说,它不是的复制品,而是相似的 以下代码:Angular Typescript Reflect.getMetadata设计:类型返回对象,而不是没有角度测试台的日期,angular,typescript,reflection,reflect-metadata,Angular,Typescript,Reflection,Reflect Metadata,首先,我想说,它不是的复制品,而是相似的 以下代码: import {} from 'reflect-metadata'; import 'core-js/es7/reflect'; function test(target: any, key: string) { console.log(key, Reflect.getMetadata('design:type', target, key).name); } class Class { } class Test { @t
import {} from 'reflect-metadata';
import 'core-js/es7/reflect';
function test(target: any, key: string) {
console.log(key, Reflect.getMetadata('design:type', target, key).name);
}
class Class { }
class Test {
@test item: String;
@test date: Date;
@test instance: Class;
}
如果使用ts摩卡测试运行。ts
输出
item Object
date Object
instance Class
而如果使用作为angular2项目输出一部分设置的karma start
运行
item String
date Date
instance Class
为什么会这样?如何使测试结果一致
(karma配置是从angular2项目中提取的,没有清理)我可以修复一个bug,但我不知道如何修复另一个bug,因为我找不到这种类型的基元类型。因为类型只存在于typescript中,在javascript中没有类型。字符串的类型不是对javascript字符串类的引用,如果你想让typescript正确编译,你必须在输入端使用
string
。比如foo:string
或者foo:string
;当你写时,让string:string=string
编译器报告错误,因为左侧引用类型,右侧引用字符串构造函数,它们是不同的。对不起,我的英语不好,所以我希望你能理解我说的话。难以想象,typescript编译器会将字符串类型编译成String类,然后编译成.js文件,您可以使用tsc
编译js文件并查看结果。可以运行第三个测试,我认为用户定义的类扮演着两个角色:类的实例
&类的类型
。但是日期
&字符串
将类型
/构造函数
分为两部分:类型
作为接口“字符串”,constructor函数
通过全局变量StringConstructor
import 'reflect-metadata';
import 'core-js/es7/reflect';
function Test(expectedType: any) {
return function (target: any, key: string): void {
let type = Reflect.getOwnMetadata('design:type', target, key);
test(`${target.constructor.name} ${key}'s type should be ${expectedType.name} but was ${type.name}!`, () => {
expect(type).toBe(expectedType);
});
}
}
class TestClass {
}
class ReflectMetadataTest {
@Test(String) item: string;
@Test(Date) date: Date;
@Test(TestClass) instance: TestClass;
}
test('metadata', () => {
let type = String;
let clazz = ReflectMetadataTest.prototype;
let decorator: any = Reflect.metadata("foo", type);
decorator(clazz, 'item', void 0);
expect(Reflect.getMetadata('foo', clazz, 'item')).toBe(type);
});
也许下面的两个测试可以回答你的问题
Date
&String
是遗留系统。它们通过函数或类声明定义类,因此typescript无法获取类型信息。然后,如果在内存中运行typescript,typescript将传递对象
类型,但是,当tsc
将.ts编译为.js时,它将类型
保留为与构造函数函数
相同。下面的测试是假设函数Foo
是基于函数的类,类型脚本无法推断Foo
类型,因此它会发出一个对象
来反映.metadata(),但当您通过tsc
将测试文件编译到.js中时,编译器将保留类型
到构造函数
import 'reflect-metadata';
import 'core-js/es7/reflect';
function Test(expectedType: any) {
return function (target: any, key: string): void {
let type = Reflect.getOwnMetadata('design:type', target, key);
test(`${target.constructor.name} ${key}'s type should be ${expectedType.name} but was ${type.name}!`, () => {
expect(type).toBe(expectedType);
});
}
}
function Foo() {
}
interface Foo {
}
class ReflectMetadataTest {
@Test(Foo/*ref function*/) foo: Foo/*ref interface*/;
}
test('metadata', () => {
let type = Foo;
let clazz = ReflectMetadataTest.prototype;
let decorator: any = Reflect.metadata("foo", type);
decorator(clazz, 'item', void 0);
expect(Reflect.getMetadata('foo', clazz, 'item')).toBe(type);
});
总结
如果要使元数据在.js和.ts中都能正确工作,则必须使用基于旧函数的类定义包装类
/子类
import 'reflect-metadata';
import 'core-js/es7/reflect';
function Test(expectedType: any, same: boolean) {
return function (target: any, key: string): void {
let declaredType = Reflect.getOwnMetadata('design:type', target, key);
test(`${target.constructor.name} ${key}'s type should ${same ? '' : 'not '}be \`${expectedType.name}\` & declared type was \`${declaredType.name}\`!`, () => {
expect(declaredType == expectedType).toBe(same);
});
}
}
function Foo() {
}
interface Foo {
}
class MyDate extends Date{
}
class ReflectMetadataTest {
// this test always false even if you compile .ts it into .js file
@Test(Foo/*ref function*/, false) foo: Foo/*ref interface*/;
//this test is true when you compile .ts it into .js file
@Test(Date, false) date: Date;
@Test(String, false) String: String;
@Test(Number, false) Number: Number;
//this test is always true both in .ts & .js
@Test(Number, true) number: number;
@Test(Boolean, true) boolean: boolean;
@Test(String, true) string: string;
@Test(MyDate, true) myDate: MyDate;
@Test(ReflectMetadataTest, true) test: ReflectMetadataTest;
}
这部分解释了为什么它不应该在内置类型上工作,以及如何解决字符串问题。这并不能解释为什么我使用karma+phantomjs在angular2测试台上运行测试时正确识别日期…日期<代码>也是同样的问题。因为typescript无法在内存中描述日期类型,所以它将<代码>对象<代码>传递给装饰器,也不会将日期<代码>传递给装饰器,这可能是typescript的一个缺陷?但是用户定义的类结合了两个部分type
和class
,因此编译器可以在内存中正确地传递它。好的,那么你是说在karma/phantomjs中,日期传递给装饰器而不是对象,因为类在某个地方被重新定义了?我的问题是,当我使用karma/phantomjs时,它为什么会起作用?因为ts mocha
没有编译成js,它直接在内存中运行测试。另一个编译成.js可能是通过webpack
/babel
。我想我可以回答你的问题,Date
&String
是遗留系统。它们通过函数或类声明定义类,因此typescript无法获取类型信息。然后,如果在内存中运行typescript,typescript将传递对象
类型,但是,当tsc
将.ts编译为.js时,它保留类型
,与构造函数一样。