Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent reflected enum types with --transpile-only enabled / disabled #873

Closed
LeoBakerHytch opened this issue Aug 24, 2019 · 1 comment

Comments

@LeoBakerHytch
Copy link

LeoBakerHytch commented Aug 24, 2019

Problem

When running ts-node --transpile-only, a class field declared with an imported (string) enum gets annotated as an Object, rather than the expected String.

This causes a problem with typegoose, which uses decorators to annotate a MongoDB / Mongoose database schema. Its prop decorator runs some validations to ensure consistency between the specified field type and the constraints provided in the decorator options.

Specifically, it checks that a field decorated with @prop({ enum: MyStringEnum }) is actually a string field. With --transpile-only enabled, this check always fails (this validation was added fairly recently: szokodiakos/typegoose@7418c34).

Repro

Can be cloned from https://gist.github.com/LeoBakerHytch/a45a6ed03b27807def5ec799d5a56c26

index.ts:

import 'reflect-metadata';
import { ExternalEnum } from './enum-metadata';

enum LocalEnum {
    bar = 'bar'
}

class Class {
    @prop()
    local: LocalEnum; // OK

    @prop()
    external: ExternalEnum; // Errors only with --transpile-only: Type === Object
}

function prop() {
    return function (target, key) {
        const Type = Reflect.getMetadata('design:type', target, key);
        if (Type !== String) {
            throw Error(`Expected String for field "${key}"; got ${Type.name}`);
        }
    };
}

enum-metadata.ts:

export enum ExternalEnum {
    foo = 'foo'
}

package.json scripts:

  "scripts": {
    "ok": "ts-node index.ts",
    "ok2": "ts-node --transpile-only --type-check index.ts",
    "error": "ts-node --transpile-only index.ts"
  },

Compiled output

For comparison, TypeScript does emit the correct output when transpiling with isolatedModules: true:

    tslib_1.__decorate([
        prop(),
        tslib_1.__metadata("design:type", String) // <—— what we want
    ], Class.prototype, "external");

index.js:

"use strict";
exports.__esModule = true;
var tslib_1 = require("tslib");
require("reflect-metadata");
var enum_metadata_1 = require("./enum-metadata");
var LocalEnum;
(function (LocalEnum) {
    LocalEnum["bar"] = "bar";
})(LocalEnum || (LocalEnum = {}));
var Class = /** @class */ (function () {
    function Class() {
    }
    tslib_1.__decorate([
        prop(),
        tslib_1.__metadata("design:type", String)
    ], Class.prototype, "local");
    tslib_1.__decorate([
        prop(),
        tslib_1.__metadata("design:type", String)
    ], Class.prototype, "external");
    return Class;
}());
function prop() {
    return function (target, key) {
        var Type = Reflect.getMetadata('design:type', target, key);
        if (Type !== String) {
            throw Error("Expected String for field \"" + key + "\"; got " + Type.name);
        }
    };
}

Solution?

Is there any way around this other than enabling --type-check or disabling --transpile-only? (I’m not actually clear on whether those two flags are complementary — does it make any sense to use both flags?)

We have been using --transpile-only as restarts of our server are incredibly slow without it... it would be a shame to have to disable it.

Related

The relavant Typegoose issue is szokodiakos/typegoose#196.

I’m not sure where the best place is to solve this issue. The additional validation added in Typegoose to ensure consistency of field types & constraints makes sense, so I wouldn’t really like to suggest that it be weakened for the sake of an environment-specific problem.

@blakeembrey
Copy link
Member

You would only need one of either --type-check or --transpile-only (--type-check is there for backward compatibly and not documented anywhere as far as I know).

Unfortunately this is just how the TypeScript compiler works. For certain use-cases (such as these enums), TypeScript requires type information to compile correctly. If it needs type information, --transpile-only will be incapable of generating the expected output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants