打字稿 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 classthe type of the class。但是Date & Stringtype/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);
});

也许下面的两个测试可以回答您的问题

DateString 是遗留的 system.they 通过函数或 class 声明定义 class,因此打字稿无法获取类型 information.then 打字稿如果你在内存中 运行 打字稿传递 Object 类型,但是,当 tsc 将 .ts 编译成 .js 时,它保留 typeconstructor function 。下面的测试假设函数 Foo 是一个基于 class 的函数,打字稿无法推断出 Foo 类型,因此它发出一个 Object 到 Reflect.metadata(),但是当你通过 tsc 将测试文件编译成 .js 时,编译器将保留 typeconstructor 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;
}