1

我想首先说它不是Typescript Reflect.getMetadata('design:type'..) return Object 而不是 Date 如果使用 Angular 2 Stack的副本但相似。

以下代码:

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-mocha test.ts输出

item Object
date Object
instance Class

而如果运行karma start它被设置为angular2项目输出的一部分

item String
date Date
instance Class

为什么会这样以及如何使测试结果保持一致?

https://gitlab.com/sQu1rr/test-ts-date-reflect/tree/master(karma 配置是从 angular2 项目中提取的,没有清理)

4

1 回答 1

1

我可以修复一个错误,但另一个我不知道如何修复,因为我找不到这种类型的原始类型。因为类型只存在于打字稿中,在 javascript 中没有类型。字符串的类型is not reference to javascript String class,如果要让typescript正确编译必须string在typesides中使用。like foo:stringnor foo:String;当你编写let string: String = String;编译器报告错误时,因为左侧ref一个类型,右侧ref一个String构造函数,它们是不同。对不起,我的英语不好,所以我希望你能理解我所说的。难以想象,打字稿编译器会将String类型编译成String类到.js文件中,你可以使用tsc编译js文件看看结果。第三次测试可以运行,我认为用户定义的类扮演两个角色:the instance of the class&the type of the class.but Date&Stringtype/constructor function分成两部分:type作为接口“字符串”,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它们通过函数或类声明定义类,因此打字稿无法获取类型信息。Object如果你在内存中运行打字稿,打字稿会传递类型,但是,当将tsc.ts 编译成 .js 时,它会保留与下面的测试type相同,constructor function假设该函数Foo是一个基于函数的类,打字稿无法推断Foo类型,因此它会发出一个Object到 Reflect.metadata(),但是当您将测试文件编译为 .js 时通过tsc,编译器将保留typeto 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 中正常工作,您必须使用a wrapper class/定义。a subclasslegacy function based class

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;
}
于 2017-03-13T22:29:19.473 回答