Làm cách nào để chuyển đổi một chuỗi thành enum trong TypeScript?


312

Tôi đã định nghĩa enum sau trong TypeScript:

enum Color{
    Red, Green
}

Bây giờ trong chức năng của tôi, tôi nhận được màu dưới dạng một chuỗi. Tôi đã thử đoạn mã sau:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

Làm thế nào tôi có thể chuyển đổi giá trị đó thành enum?

Câu trả lời:


431

Enums trong TypeScript 0.9 là chuỗi + số dựa trên. Bạn không cần xác nhận loại cho các chuyển đổi đơn giản:

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

Dùng thử trực tuyến

Tôi có tài liệu về điều này và các mẫu Enum khác trong cuốn sách OSS của tôi: https://basarat.gitbook.io/typescript/type-system/enums


112
Điều này không hoạt động với --noImplicitAny(trong VS không được chọn "Cho phép ẩn 'bất kỳ loại nào"). Nó tạo ra error TS7017: Index signature of object type implicitly has an 'any' type.cho tôi cái này hoạt động: var color: Color = (<any>Color)[green];(đã thử nghiệm với phiên bản 1.4)
Vojta

3
@Vojta nói đúng. Nó không hoạt động trong VS 2012. Cái này hoạt động nhưng var color: Color = (<any> Color) [green];
Faisal Mq

3
Nó cũng không hoạt động ở đây, tài liệu chính thức dường như xác nhận rằng: typecriptang.org/docs/handbook/release-notes/ Kẻ
Pieter De Bie

26
Đảm bảo sử dụng cái này nếu --noImplicitAny var color : Color = Color[green as keyof typeof Color];
Jonas

2
@ Naxos84 Xem câu trả lời của tôi stackoverflow.com/a/56076148/294242
Jonas

123

Kể từ khóa Kiểu chữ 2.1 trong enums được gõ mạnh. keyof typeofđược sử dụng để nhận thông tin về các khóa chuỗi có sẵn ( 1 ):

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];

https://www.typescriptlang.org/docs/handbook/advified-types.html#index-types


4
Vì vậy, chúng ta có thể sử dụng typecast:let s = "Green"; let typedColor = <keyof typeof Color> s;
SergeyT

Đúng, và thay thế letbằng constsẽ làm việc mà không cần đúc. Cập nhật ví dụ để làm rõ điều này. Cảm ơn @SergeyT
Victor

1
typedColorString = Color["Black"];bây giờ trở lạierror TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
Dominik

2
Câu trả lời một dòng:const color: Color = Color[colorString as keyof typeof Color];
cscan

38

Nếu bạn chắc chắn rằng một chuỗi đầu vào có khớp chính xác với Color enum thì hãy sử dụng:

const color: Color = (<any>Color)["Red"];

Trong trường hợp chuỗi đầu vào có thể không khớp với Enum, hãy sử dụng:

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}

Sân chơi


Nếu chúng ta không truyền enumđể <any>gõ thì TypeScript sẽ hiển thị lỗi:

Phần tử ngầm có loại 'bất kỳ' vì biểu thức chỉ mục không phải là loại 'số'.

Điều đó có nghĩa là theo mặc định, kiểu TypeScript Enum hoạt động với các chỉ mục số, nghĩa là let c = Color[0], nhưng không phải với các chỉ mục chuỗi như thế nào let c = Color["string"]. Đây là một hạn chế đã biết của nhóm Microsoft đối với các chỉ mục chuỗi đối tượng có vấn đề chung hơn .


Bạn cũng có thể chuyển sang <keyof typeof Color>. Ngoài ra "0" cũng nhập sai nhưng sẽ không trả về không xác định, vì vậy hãy kiểm tra typeof mayBeColor === 'number'
Quentin 2

@ Quentin2 còn một chuỗi số thì sao? tức là typeof '0'nênstring
Patrick Michaelsen

36
enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green as keyof typeof Color]; //Works with --noImplicitAny

Ví dụ này hoạt động với --noImplicitAnytrong TypeScript

Nguồn:
https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advified-types.html#index-types


Tôi không biết tại sao, nhưng giải pháp này không hoạt động trên const enum (sử dụng Bản mô tả 3.8.3)
Robin-Hoodie

30

Lưu ý này liên quan đến câu trả lời của basarat , không phải câu hỏi ban đầu.

Tôi đã gặp một vấn đề kỳ lạ trong dự án của riêng mình, nơi trình biên dịch đã đưa ra một lỗi gần tương đương với "không thể chuyển đổi chuỗi thành Màu" bằng cách sử dụng tương đương với mã này:

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

Tôi thấy rằng kiểu suy luận của trình biên dịch đang bị lẫn lộn và nó nghĩ rằng đó colorIdlà một giá trị enum chứ không phải ID. Để khắc phục sự cố, tôi phải sử dụng ID dưới dạng chuỗi:

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

Tôi không chắc điều gì đã gây ra sự cố nhưng tôi sẽ để lại ghi chú này ở đây trong trường hợp có ai gặp phải vấn đề tương tự tôi đã làm.


Cảm ơn bạn! Đây là một vấn đề khá ngớ ngẩn và khó để tìm ra vấn đề là gì. Bản mẫu có thể xem xét đưa ra một cách xử lý tốt hơn.
GàFeet

25

Tôi đã làm cho nó hoạt động bằng cách sử dụng mã sau đây.

var green= "Green";
var color : Color= <Color>Color[green];

23

Nếu bạn cung cấp các giá trị chuỗi cho enum của bạn, một cast thẳng hoạt động tốt.

enum Color {
  Green = "Green",
  Red = "Red"
}

const color = "Green";
const colorEnum = color as Color;

1
Rất đơn giản. Đẹp!
Bernoulli IT

1
Điều này có thể gây hiểu nhầm vì nó không bảo vệ chống lại màu sắc không hợp lệ. const colorEnum = "Blue" as Colorsẽ không có lỗi, và bạn sẽ không còn suy nghĩ gì nữa colorEnum. Nhưng nếu bạn đã ở console.logđó, bạn sẽ thấy "Màu xanh". Câu trả lời của Artru là tốt, bởi vì colorEnumsẽ được undefined- và sau đó bạn có thể kiểm tra cụ thể.
M Falanga

20

Cho bạn sử dụng bản in: Nhiều giải pháp ở trên có thể không hoạt động hoặc quá phức tạp.

Tình huống : Các chuỗi không giống với các giá trị enum (vỏ khác nhau)

enum Color {
  Green = "green",
  Red = "red"
}

Chỉ dùng:

const color = "green" as Color

15

Tôi cũng chạy vào lỗi trình biên dịch tương tự. Chỉ là một biến thể ngắn hơn của cách tiếp cận của Sly_cardinal.

var color: Color = Color[<string>colorId];

Ngoài ra: Trong trường hợp bạn có một enum bản thảo được điền bởi một lớp javascript nối tiếp enum dưới dạng chuỗi (ví dụ: API Web Asp qua AngularJS), bạn có thể thực hiện myProp.color = Color[<string><any>myProp.color] Cheers
Victor

1
Đây phải là câu trả lời được công nhận.
Miroslav Popov

9

Nếu trình biên dịch TypeScript biết rằng loại biến là chuỗi thì điều này hoạt động:

let colorName : string = "Green";
let color : Color = Color[colorName];

Nếu không, bạn nên chuyển đổi nó thành một chuỗi (để tránh các cảnh báo của trình biên dịch):

let colorName : any = "Green";
let color : Color = Color["" + colorName];

Tại thời gian chạy cả hai giải pháp sẽ làm việc.


3
Tại sao không chỉ sử dụng typecast <string>colorNamethay vì "" + colorName?
SergeyT

7

Có rất nhiều thông tin lẫn lộn trong câu hỏi này, vì vậy, hãy bao quát toàn bộ việc triển khai cho TypeScript 2.x + trong Hướng dẫn sử dụng Enums trong Mô hình với TypeScript .

Hướng dẫn này dành cho: những người đang tạo mã phía máy khách đang sử dụng một chuỗi các chuỗi đã biết từ máy chủ sẽ được mô hình hóa một cách thuận tiện như một Enum ở phía máy khách.

Xác định enum

Hãy bắt đầu với enum. Nó sẽ trông giống như thế này:

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

Hai điều cần lưu ý ở đây:

  1. Chúng tôi tuyên bố rõ ràng đây là các trường hợp enum được hỗ trợ chuỗi cho phép chúng tôi khởi tạo chúng bằng các chuỗi chứ không phải một số số không liên quan khác.

  2. Chúng tôi đã thêm một tùy chọn có thể tồn tại hoặc không tồn tại trên mô hình máy chủ của chúng tôi : UNKNOWN. Điều này có thể được xử lý như undefinedthể bạn thích, nhưng tôi muốn tránh | undefinedcác loại bất cứ khi nào có thể để đơn giản hóa việc xử lý.

Điều tuyệt vời khi có một UNKNOWNtrường hợp là bạn có thể thực sự rõ ràng về nó trong mã và tạo kiểu cho các trường hợp enum chưa biết màu đỏ sáng và mờ để bạn biết rằng bạn không xử lý một cái gì đó chính xác.

Phân tích enum

Bạn có thể đang sử dụng enum này được nhúng trong một mô hình khác, hoặc một mình, nhưng bạn sẽ phải phân tích chuỗi enum được gõ từ JSON hoặc XML (ha) vào đối tác được gõ mạnh của bạn. Khi được nhúng trong một mô hình khác, trình phân tích cú pháp này sống trong hàm tạo của lớp.

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}

Nếu enum được phân tích cú pháp chính xác, nó sẽ trở thành loại thích hợp. Nếu không, nó sẽ được undefinedvà bạn có thể chặn nó và trả lại UNKNOWNtrường hợp của bạn . Nếu bạn thích sử dụng undefinednhư trường hợp không xác định của mình, bạn có thể trả về bất kỳ kết quả nào từ phân tích enum đã thử.

Từ đó, vấn đề chỉ là sử dụng hàm phân tích cú pháp và sử dụng biến được gõ mạnh mới của bạn.

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

6
Thật không may, điều này dường như là không chính xác hoặc, ít nhất, không khái quát. Nó hoạt động vì các khóa của bạn bằng với chuỗi mà chúng được gán. Nếu họ, như trong trường hợp của tôi, tuy nhiên, điều này không hoạt động. Theo lời của tài liệu : "Hãy nhớ rằng các thành viên chuỗi enum hoàn toàn không có được ánh xạ ngược." Mã của bạn sẽ biên dịch thành một cái gì đó như IssueType["REPS"]="REPS". Nếu bạn đã xác định enum của mình một chút khác biệt, giả sử, REPS="reps"điều này sẽ mang lại IssueType["REPS"]="reps"...
altocumulus

... Luôn luôn quay trở lại IssueType.UNKNOWNvì không có chìa khóa repstrong enum của bạn. Quá tệ, tôi vẫn không tìm thấy giải pháp nào cho việc này vì các chuỗi của tôi chứa các dấu gạch nối khiến chúng không thể sử dụng làm khóa.
altocumulus

Cuối cùng, tôi tìm thấy một giải pháp trong câu trả lời này bằng cách thuyết phục trình biên dịch rằng đây không phải là một chuỗi enum. Có thể đáng để chỉnh sửa thông tin này vào câu trả lời của riêng bạn.
altocumulus

7

Tôi đang tìm kiếm một câu trả lời có thể nhận được enumtừ a string, nhưng trong trường hợp của tôi, các giá trị enums có các giá trị chuỗi khác nhau. OP có một enum đơn giản cho Color, nhưng tôi có một cái gì đó khác:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

Khi bạn cố gắng giải quyết Gender.CantTellbằng một "Can't tell"chuỗi, nó sẽ trả về undefinedvới câu trả lời ban đầu.

Một câu trả lời khác

Về cơ bản, tôi đã đưa ra một câu trả lời khác, được truyền cảm hứng mạnh mẽ bởi câu trả lời này :

export const stringToEnumValue = <ET, T>(enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

Ghi chú

  • Chúng tôi lấy kết quả đầu tiên của filter, giả sử khách hàng được thông qua một chuỗi hiệu lực kể từ enum. Nếu không phải như vậy, undefinedsẽ được trả lại.
  • Chúng tôi đúc enumObjđến any, bởi vì với nguyên cảo 3.0 trở lên (hiện đang sử dụng nguyên cảo 3.5), các enumObjđã được giải quyết như unknown.

Ví dụ về sử dụng

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue<typeof Gender, Gender>(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

Lưu ý: Và, như ai đó đã chỉ ra trong một bình luận, tôi cũng muốn sử dụng noImplicitAny.

Phiên bản cập nhật

Không có diễn viên anyvà đánh máy thích hợp.

export const stringToEnumValue = <T, K extends keyof T>(enumObj: T, value: string): T[keyof T] | undefined =>
  enumObj[Object.keys(enumObj).filter((k) => enumObj[k as K].toString() === value)[0] as keyof typeof enumObj];

Ngoài ra, phiên bản cập nhật có cách gọi dễ dàng hơn và dễ đọc hơn:

stringToEnumValue(Gender, "Can't tell");

6

Tôi cần phải biết cách lặp lại các giá trị enum (đã thử nghiệm nhiều hoán vị của một số enum) và tôi thấy điều này hoạt động tốt:

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

Nguồn: https://blog.mikeki.net/development/javascript/typescript-enums-to-from-opes/


Câu trả lời này là tuyệt vời! Yêu nó. Đặc biệt là cách bạn thực hiện một enum ra khỏi chuỗi. Điều này có thể giúp bạn tiết kiệm rất nhiều khi gõ khi kiểm tra enums hoặc các trường hợp khác.
Florian Leit Quay

Có, tôi sử dụng điều này với Jest eachđể kiểm tra từng trường hợp enum chỉ với một phương thức
mikeb

3

Enum

enum MyEnum {
    First,
    Second,
    Three
}

Sử dụng mẫu

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

Bỏ qua phân tích cú pháp nhạy cảm

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}

Bất cứ ai có enum như tôi nên đặt return enumType[property];trong trường hợp khi vật phẩm enum của bạn trông giống nhưSkills = "anyvalue"
neustart47

@ neustart47 bạn có thể vui lòng đặt câu hỏi không?
ấn tượng vào

Đó không phải là một câu hỏi. Tôi chỉ đề cập đến một số thay đổi cho bất cứ ai đang tìm kiếm trường hợp tương tự như tôi có. Câu trả lời của bạn là đúng.
neustart47

2

Enums được tạo theo cách bạn đã làm được biên dịch thành một đối tượng lưu trữ cả ánh xạ thuận (name -> value)và ngược (value -> name). Như chúng ta có thể quan sát từ ảnh chụp màn hình chrome devtools này:

nhập mô tả hình ảnh ở đây

Dưới đây là một ví dụ về cách hoạt động của ánh xạ kép và cách truyền từ cái này sang cái khác:

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1

1

Thử cái này

màu var: Color = (Màu như bất kỳ) ["Green];

Điều đó hoạt động tốt cho phiên bản 3.5.3


0

Nếu bạn đang sử dụng không gian tên để mở rộng chức năng của enum thì bạn cũng có thể làm một cái gì đó như

    enum Color {
        Red, Green
    }

    export namespace Color {
      export function getInstance(color: string) : Color {
        if(color == 'Red') {
          return Color.Red;
        } else if (color == 'Green') {
          return Color.Green;
        }
      }
    }

và sử dụng nó như thế này

  Color.getInstance('Red');

0

biến thể khác có thể là

const green= "Green";

const color : Color = Color[green] as Color;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.