打字稿库如何在运行时设法读取类型

How do typescript libraries manage to read types at runtime

当源代码从 typescript 编译为 javascript 时,类型注释被剥离,并且无法在运行时检查变量的类型。

但是,有许多打字稿库似乎会根据 class 属性的类型注释更改行为。例如,在编写 typeorm 实体时,我们可以这样写:

@Entity()
class MyEntity extends BaseEntity {
  @Field()
  public id: number // automatically infers int database type

  @Field()
  public description: string // automatically infers varchar or text database type

  @Field()
  public image: string | null // cannot infer correct type, will throw error

}

我们也有与 typedi(通过构造函数传递正确的引用)、type-graphql(使用正确的 graphql 类型构建 graphql 模式)等类似的东西。当你必须通过装饰器或类似的东西传递函数时,我明白了,但是这些库如何仅从类型注释推断类型?

我很好奇,在 TypeORM 文档中找到了答案 here:

TypeScript configuration

Also, make sure you are using TypeScript version 4.5 or higher, and you have enabled the following settings in tsconfig.json:

"emitDecoratorMetadata": true,
"experimentalDecorators": true,

我怀疑是告诉 TypeScript 向装饰器提供运行时类型信息,事实上,it does:

Emit Decorator Metadata

emitDecoratorMetadata

Enables experimental support for emitting type metadata for decorators which works with the module reflect-metadata.

启用后,TypeScript 会在运行时发出对包含类型信息的装饰器的调用。文档中的示例适用于此代码:

class Demo {
  @LogMethod
  public foo(bar: number) {
    // do nothing
  }
}

...发出 __decorate__metadata 函数,然后是:

class Demo {
    foo(bar) {
        // do nothing
    }
}
__decorate([
    LogMethod,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Number]),
    __metadata("design:returntype", void 0)
], Demo.prototype, "foo", null);

如果我们查看您的示例,这就是它为装饰器调用发出的内容:

__decorate([
    Field(),
    __metadata("design:type", Number)
], MyEntity.prototype, "id", void 0);
__decorate([
    Field(),
    __metadata("design:type", String)
], MyEntity.prototype, "description", void 0);
__decorate([
    Field(),
    __metadata("design:type", Object)
], MyEntity.prototype, "image", void 0);
MyEntity = __decorate([
    Entity()
], MyEntity);

Playground link