2016-03-02 13 views
13

Có cách nào để có EnScript kiểu tương thích với chuỗi từ JSON không?Các kiểu chữ `enum` từ chuỗi JSON

Ví dụ:

enum Type { NEW, OLD } 

interface Thing { type: Type } 

let thing:Thing = JSON.parse('{"type": "NEW"}'); 

alert(thing.type == Type.NEW); // false 

tôi sẽ nhưthing.type == Type.NEW đến mức khó tin. Hoặc cụ thể hơn, tôi muốn tôi có thể chỉ định các giá trị enum được xác định là chuỗi, không phải số.

Tôi biết rằng tôi có thể sử dụng thing.type.toString() == Type[Type.NEW] nhưng điều này là cồng kềnh và dường như làm cho chú thích loại enum gây nhầm lẫn và gây nhầm lẫn, đánh bại mục đích của nó. JSON về mặt kỹ thuật là không phải cung cấp giá trị enum hợp lệ, vì vậy tôi không nên nhập thuộc tính vào enum.

Vì vậy, những gì tôi hiện đang làm thay vì đang sử dụng một loại chuỗi với các hằng số tĩnh:

const Type = { NEW: "NEW", OLD: "OLD" } 

interface Thing { type: string } 

let thing:Thing = JSON.parse('{"type": "NEW"}'); 

alert(thing.type == Type.NEW); // true 

này được tôi sử dụng tôi muốn, nhưng kiểu chú thích string là cách quá rộng và dễ bị lỗi.

Tôi hơi ngạc nhiên khi một tập hợp siêu nhỏ của JavaScript không có chuỗi dựa trên enums. Tui bỏ lỡ điều gì vậy? Có cách nào khác có thể thực hiện được không?


Update TS 1,8

Sử dụng string literal types là một lựa chọn (nhờ @basaret), nhưng để có được việc sử dụng enum như mong muốn (trên) nó đòi hỏi việc xác định giá trị của bạn hai lần: một lần trong một loại chuỗi ký tự, và một lần dưới dạng một giá trị (hằng số hoặc không gian tên):

type Type = "NEW" | "OLD"; 
const Type = { 
    NEW: "NEW" as Type, 
    OLD: "OLD" as Type 
} 

interface Thing { type: Type } 

let thing:Thing = JSON.parse(`{"type": "NEW"}`); 

alert(thing.type === Type.NEW); // true 

Điều này hoạt động nhưng tốn rất nhiều công sức, đủ để tôi không sử dụng nó nhiều nhất o f thời gian. Bây giờ tôi hy vọng proposal for string enums cuối cùng sẽ làm lộ trình.


Update TS 2.1

mới keyof type lookup phép cho chuỗi loại đen được tạo ra từ các phím của một const hoặc namespace, mà làm cho định nghĩa một dư thừa chút ít:

namespace Type { 
    export const OLD = "OLD"; 
    export const NEW = "NEW"; 
} 
type Type = keyof typeof Type; 

interface Thing { type: Type } 

const thing: Thing = JSON.parse('{"type": "NEW"}'); 
thing.type == Type.NEW // true 

Cập nhật T S 2.4

TypeScript 2.4 added support for string enums!Ví dụ trên trở thành:

enum Type { 
    OLD = "OLD", 
    NEW = "NEW" 
} 

interface Thing { type: Type } 
const thing: Thing = JSON.parse('{"type": "NEW"}'); 
alert(thing.type == Type.NEW) // true 

này trông gần hoàn hảo, nhưng vẫn có một số đau lòng:

  • Bạn vẫn phải viết giá trị gấp đôi, tức là OLD = "OLD", và không có xác nhận rằng bạn không có lỗi đánh máy, như NEW = "MEW" ... điều này đã cắn tôi bằng mã thực.
  • Có một số điều kỳ quặc (có thể là lỗi?) Với cách kiểm tra kiểu enum, nó không chỉ là viết tắt kiểu chữ, đó là điều thực sự đúng. Một số vấn đề tôi đã tình cờ gặp:

    enum Color { RED = "RED", BLUE = "BLUE", GREEN = "GREEN" } 
    
    type ColorMap = { [P in Color]: number; } 
    
    declare const color: Color; 
    declare const map: ColorMap; 
    map[color] // Error: Element implicitly has an 'any' type because type 'ColorMap' has no index signature. 
    
    const red: Color = "RED"; // Type '"RED"' is not assignable to type 'Color'. 
    const blue: Color = "BLUE" as "RED" | "BLUE" | "GREEN"; // Error: Type '"RED" | "BLUE" | "GREEN"' is not assignable to type 'Color'. 
    

    Mã tương đương với enum Color thay thế bằng chuỗi loại đen hoạt động tốt ...

Yeah, tôi nghĩ rằng tôi có OCD về vấn đề này, tôi chỉ muốn các enums JS hoàn hảo của tôi. :)

Trả lời

6

Nếu bạn đang sử dụng nguyên cảo trước khi phát hành 2.4, có một cách để đạt được điều đó với sự đếm bằng cách đúc các giá trị của enum của bạn để any.

Một example of your first implementation

enum Type { 
    NEW = <any>"NEW", 
    OLD = <any>"OLD", 
} 

interface Thing { type: Type } 

let thing:Thing = JSON.parse('{"type": "NEW"}'); 

alert(thing.type == Type.NEW); // true 

Typescript 2.4 has built in support for string enums rồi, nên các diễn viên để any sẽ không còn cần thiết và bạn có thể đạt được điều đó mà không cần dùng String Literal Union Type, đó là ok để xác nhận và autocomplete, nhưng không phải như vậy tốt cho khả năng đọc và tái cấu trúc, tùy thuộc vào tình huống sử dụng.

+0

Cảm ơn! Tôi ước gì tôi đã biết về sự khẳng định của 'bất kỳ' trước đây. Bây giờ, tôi đang cố gắng ra TS 2.4 chuỗi enums, và nó khá gần với những gì tôi ban đầu muốn ... nhưng tôi đã tìm thấy một số vấn đề với cách TS loại kiểm tra nó ... – Aaron

+0

@ Aaron mát mẻ, vui mừng để giúp đỡ! Ngoài ra, bạn có thể muốn kiểm tra dự án [ts-enums] (https://github.com/LMFinney/ts-enums) vì nó làm cho việc xử lý enum rất linh hoạt và mạnh mẽ cho nhiều trường hợp sử dụng –

0

nhưng chuỗi chú thích loại quá rộng và dễ bị lỗi.

Đồng ý. Một cách giải quyết nhanh chóng (nếu bạn có sự sang trọng của thế hệ mã bạn có thể tự động này):

interface Thing { type: "NEW" | "OLD" } 

Chúng được gọi là chuỗi literals trong một đoàn. Thêm: https://basarat.gitbooks.io/typescript/content/docs/tips/stringEnums.html

+0

Điều này có vẻ đầy hứa hẹn. Chúng tôi sẽ điều tra khi chúng tôi nâng cấp lên TS 1.8. Tôi đã chơi với nó và đã không thể làm việc ra làm thế nào để sử dụng các chuỗi giá trị chữ như hằng số, tức là một cái gì đó như 'thing.type == Type.NEW'. – Aaron

+1

[Điều này gần như tôi có thể nhận được] (http://www.typescriptlang.org/Playground#src=type%20Type%20%3D%20%22NEW%22%20%7C%20%22OLD%22% 3B% 0Thêm% 20%% 20% 3D% 20% 7B% 0A% 09NEW% 3A% 20% 22NEW% 22% 2C% 0A% 09OLD% 3A% 20% 22OLD% 22% 0A% 7D% 0A% 0 Giao diện% 20Thing% 20% 7B% 20 loại% 3A% 20 Loại% 20% 7D% 0A% 0Một% 20%% 3AThing% 20% 3D% 20JSON.parse (% 60% 7B% 22 loại% 22% 3A% 20% 22NEW% 22% 7D% 60)% 3B% 0A% 0Aalert (điều.type% 20% 3D% 3D% 3D% 20Type.NEW)% 3B), nhưng nó yêu cầu xác định 'Loại' và các giá trị hai lần, một lần là một' loại' để sử dụng làm một chú thích kiểu giao diện, và một lần nữa như một 'const' để sử dụng nơi tôi cần các giá trị. Điều này có thể được cải thiện không? – Aaron

0

Tôi đã sử dụng các chức năng chuyển đổi làm điểm dừng. Hy vọng chủ đề này nói đến một độ phân giải: https://github.com/Microsoft/TypeScript/issues/1206

enum ErrorCode { 
    Foo, 
    Bar 
} 

interface Error { 
    code: ErrorCode; 
    message?: string; 
} 

function convertToError(obj: any): Error { 
    let typed: Error = obj as Error; 

    // Fix any enums 
    typed.code = ErrorCode[typed.code.toString()]; 
    return typed; 
}