简体   繁体   中英

Enum issues in Typescript

Trying to initialize an object and trying to understand a few quirks. First, I want to partially initialize the object using the . I am encountering some strange quirks with regard to enums.

Consider this type hierarchy:

enum CalcType {
  EXPRESS,
  EXPRESS_LESS_EARNED,
  COST_BASIS
}

interface Program {
  active: boolean;
  code: string;
  displayOrder: number;
  dpld: boolean;
  calcType: CalcType;
}

this.p = <Program> {
  active: false,
  displayOrder: 100,
  dpld: true,
  calcType: CalcType[CalcType.EXPRESS_LESS_EARNED],     // Does not work in Angular!!
  //calcType: CalcType['1']       // Works, value is a string
  //calcType: CalcType.EXPRESS_LESS_EARNED      // Works, value is the ordinal
};

When I try to create/initialize a new Program using the interface type if I populate the calcType attribute using CalcType[CalcType.EXPRESS_LESS_EARNED] it works in JSBin Typescript without issues but refuses to work in Angular Typescript 2.6.1. Any ideas why? The error I get is the following:

Type '{ active: false; displayOrder: number; dpld: true; calcType: string; }' cannot be converted to type 'Program'.
  Property 'code' is missing in type '{ active: false; displayOrder: number; dpld: true; calcType: string; }'.

However, if I use CalcType.EXPRESS_LESS_EARNED or CalcType['1'] it works fine.

JSBin: http://jsbin.com/bipofim/edit?js,console

StackBlitz: https://stackblitz.com/edit/enums-test

What am I missing here? I should be able to use the Enum[ordinal] syntax to get the string value. In addition why does it complain that fields are missing in some cases and not in others?

EDIT:

Here is the issue, the HTTP service de-serializes/serializes from JSON using the syntax, where resp is the HttpResponse:

 return resp.body as Program;

During the de-serialization the strings in the JSON are converted to the enum string equivalents and not their ordinals. During serialization they expect String equivalents of enums otherwise they just get converted to numbers which the server does not understand.

So how do I get the JSON to translate enum fields based on either their string values or ordinals??

ie Downstream "EXPRESS" should convert to CalcType.EXPRESS or 1 Upstream CalcType.EXPRESS or 1 should convert to "EXPRESS"

This is primarily TypeScript problem. It will cause an error anywhere, not just in Angular. It works in JSBin because it ignores compilation errors.

There are two different problems here, with calcType and code properties.

The problem is that enum is used incorrectly here, and this can be detected with type checks.

CalcType enum is desugared to:

var CalcType;
(function (CalcType) {
    CalcType[CalcType["EXPRESS"] = 0] = "EXPRESS";
    CalcType[CalcType["EXPRESS_LESS_EARNED"] = 1] = "EXPRESS_LESS_EARNED";
    CalcType[CalcType["COST_BASIS"] = 2] = "COST_BASIS";
})(CalcType || (CalcType = {}));

It provides a map of property names and their respective numeric values and results in an object:

枚举

However this is numeric enum , and enum values are supposed to be numbers.

This is type error, enum values are supposed to be numbers, while CalcType[CalcType.EXPRESS_LESS_EARNED] is a string:

calcType: CalcType[CalcType.EXPRESS_LESS_EARNED]

This just disables type checks:

calcType: CalcType['1']

This is the way enums are supposed to be used, so it works:

calcType: CalcType.EXPRESS_LESS_EARNED

If you should be able to use the Enum[ordinal] syntax to get the string value , then string enums have to be used, and string values are supposed to be defined explicitly:

enum CalcType {
  EXPRESS = 'EXPRESS',
  ...
}

This way it's not really different than a plain object:

const CalcType = {
  EXPRESS: 'EXPRESS',
  ...
};

This error states that the object has no code , while it should exist in Program :

Property 'code' is missing in type '{ active: false; displayOrder: number; dpld: true; calcType: string; }'.

TLDR:

Change your interface to the following:

interface Program {
    active: boolean;
    code?: string;
    displayOrder: number;
    dpld: boolean;
    calcType: string;
}

Full Answer

I can't answer exactly why it's happening, but I can say how to fix some of your issues.

You've specified Program to have a non-optional parameter code which you then haven't supplied to this.p . If you make code optional ( code?: string; ), it makes your error message go away and then you get the real issue (which isn't actually an issue!).

As far as Typescript is concerned, both CalcType.EXPRESS_LESS_EARNED and CalcType['1'] return an object of type CalcType . CalcType[CalcType.EXPRESS_LESS_EARNED] , however, has a return type of string . You are violating your Program interface by assigning a string to calcType instead of a CalcType . If you change it to be calcType: string; then the rest of your problems go away.

As for your saying that CalcType[CalcType.EXPRESS_LESS_EARNED] isn't working, I have tested it in Typescript 2.61 and 2.71, and both times it has correctly equated to 'EXPRESS_LESS_EARNED' as a string .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM