打字稿 Reflect.getMetadata design:type returns 对象而不是没有 angular 测试平台的日期
Typescript Reflect.getMetadata design:type returns Object instead of Date without angular testbed
首先我想说它不是 Typescript Reflect.getMetadata('design:type'..) returns Object instead of Date if the Angular 2 Stack is used 的副本,但很相似。
以下代码:
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;
}
if 运行 with ts-mocha test.ts
outputs
item Object
date Object
instance Class
while if 运行 with karma start
设置为 angular2 项目输出的一部分
item String
date Date
instance Class
为什么会这样,如何使测试结果一致?
https://gitlab.com/sQu1rr/test-ts-date-reflect/tree/master(karma配置是从一个angular2项目中提取出来的,没有清理)
我可以修复一个错误,但另一个我不知道如何修复,因为我找不到这样的原始类型 type.because 类型只存在于打字稿中,在 javascript 没有 type.the 类型的字符串不是对 javascript 字符串 class 的引用,如果你想让 typescript 正确编译你必须在类型 [=55= 中使用 string
] foo:string
也不是 foo:String
; 当你写 let string: String = String;
编译器报错,因为左边引用了一个类型,右边引用了一个 String 构造函数,它们是 different.I' sorry,我的英语不好,所以我希望你能理解我是什么said.unimaginable,打字稿编译器会将String类型编译成String class到.js文件中,你可以使用tsc
编译 js 文件并查看 result.the 第三个测试可能是 运行,我认为用户定义的 class 扮演两个角色:the instance of the class
和 the type of the class
。但是Date
& String
将 type
/constructor function
分为两部分: type
作为接口 'String', constructor function
通过全局变量 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
是遗留的 system.they 通过函数或 class 声明定义 class,因此打字稿无法获取类型 information.then 打字稿如果你在内存中 运行 打字稿传递 Object
类型,但是,当 tsc
将 .ts 编译成 .js 时,它保留 type
与constructor function
。下面的测试假设函数 Foo
是一个基于 class 的函数,打字稿无法推断出 Foo
类型,因此它发出一个 Object
到 Reflect.metadata(),但是当你通过 tsc
将测试文件编译成 .js 时,编译器将保留 type
到 constructor function
.
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 中都正常工作,你必须用 legacy function based class
.
定义 a wrapper class
/a subclass
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;
}
首先我想说它不是 Typescript Reflect.getMetadata('design:type'..) returns Object instead of Date if the Angular 2 Stack is used 的副本,但很相似。
以下代码:
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;
}
if 运行 with ts-mocha test.ts
outputs
item Object
date Object
instance Class
while if 运行 with karma start
设置为 angular2 项目输出的一部分
item String
date Date
instance Class
为什么会这样,如何使测试结果一致?
https://gitlab.com/sQu1rr/test-ts-date-reflect/tree/master(karma配置是从一个angular2项目中提取出来的,没有清理)
我可以修复一个错误,但另一个我不知道如何修复,因为我找不到这样的原始类型 type.because 类型只存在于打字稿中,在 javascript 没有 type.the 类型的字符串不是对 javascript 字符串 class 的引用,如果你想让 typescript 正确编译你必须在类型 [=55= 中使用 string
] foo:string
也不是 foo:String
; 当你写 let string: String = String;
编译器报错,因为左边引用了一个类型,右边引用了一个 String 构造函数,它们是 different.I' sorry,我的英语不好,所以我希望你能理解我是什么said.unimaginable,打字稿编译器会将String类型编译成String class到.js文件中,你可以使用tsc
编译 js 文件并查看 result.the 第三个测试可能是 运行,我认为用户定义的 class 扮演两个角色:the instance of the class
和 the type of the class
。但是Date
& String
将 type
/constructor function
分为两部分: type
作为接口 'String', constructor function
通过全局变量 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
是遗留的 system.they 通过函数或 class 声明定义 class,因此打字稿无法获取类型 information.then 打字稿如果你在内存中 运行 打字稿传递 Object
类型,但是,当 tsc
将 .ts 编译成 .js 时,它保留 type
与constructor function
。下面的测试假设函数 Foo
是一个基于 class 的函数,打字稿无法推断出 Foo
类型,因此它发出一个 Object
到 Reflect.metadata(),但是当你通过 tsc
将测试文件编译成 .js 时,编译器将保留 type
到 constructor function
.
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 中都正常工作,你必须用 legacy function based class
.
a wrapper class
/a subclass
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;
}