打字稿泛型中的自定义枚举过于复杂

时间:2018-04-18 14:43:16

标签: typescript enums typescript-generics

如果有更简单的方法将其写下来,因为这是非常重复的,而且看起来非常错误......

<main>

我希望IDE能够告诉我,const FolderVisibility = new Enum<{ PUBLIC: 'public', PRIVATE: 'private' }>({ PUBLIC: 'public', PRIVATE: 'private' }) as Enum<{ PUBLIC: 'public', PRIVATE: 'private' }> & { PUBLIC: 'public', PRIVATE: 'private' } 作为参数无论如何都是只读的。

这是FolderVisibility.PUBLIC == 'public'类,它有很少的属性和一个函数

Enum

关键是,如果我复制构造函数中使用的对象4次,它甚至会告诉我export default class Enum<T extends { [index: string]: string }> { private readonly map: T; public readonly values: (T[keyof T])[]; constructor(enums: T) { Object.defineProperty(this, 'map', { value: {} }); for (let prop in enums) { if (enums.hasOwnProperty(prop)) { const value = enums[prop] if(typeof value != 'string'){ throw new EnumError(value) } this.map[prop] = value Object.defineProperty(this, prop, { value }); } } Object.defineProperty(this, 'values', { value: Object.values(this.map) }); } isValid(text: any) { if (!text) return true return this.values.includes(text) } } 类型为FolderVisibility.values

PS:我试过这个,但它会为'public' | 'private'提供string。还有,它还很长。     const data = {         PUBLIC:&#39; public&#39;,         私人:&#39;私人&#39;     }

FolderVisibility.values

1 个答案:

答案 0 :(得分:4)

对象文字和文字类型的问题在于,您无法让编译器推断对象文字属性的文字类型。这就是为什么指定泛型类型参数是必要的。

你的方法中有一部分肯定可以简化,那就是枚举后的演员表。不要使用构造函数,使用一个简单的函数,因为它可以返回更多的灵活性:

function Enum<T extends{ [P in keyof T]: string }>(enums: T) {

    let map : { [index: string]: string } = {}

    for (let prop in enums) {
        if (enums.hasOwnProperty(prop)) {
            const value = enums[prop]
            if(typeof value != 'string'){
                throw new EnumError(value)
            }
            map[prop] = value;
        }
    }
    let result = Object.assign({}, enums , {
        values: Object.values(map),
        isValid(text: string) {
            if (!text) return true
            return this.values.includes(text)
        }
    });
    // maybe frees the enum so no values are chanegd ?
    return Object.freeze(result);
}
const FolderVisibility = Enum<{
    PUBLIC: 'public',
    PRIVATE: 'private'
}>({
    PUBLIC: 'public',
    PRIVATE: 'private'
});
console.log(FolderVisibility.isValid("")) // Works
console.log(FolderVisibility.PRIVATE === "private" ) // And const fields of string literal type

我们还可以使用上面的函数来扩充实际的枚举,需要更少的显式输入:

enum FolderVisibilityProto {
    PUBLIC ='public',
    PRIVATE=  'private'
}
const FolderVisibility = Enum(FolderVisibilityProto);

或者我们可以稍微更改Enun函数以进行内部创建枚举的回调,以便无法访问非扩充枚举:

function Enum<T extends{ [P in keyof T]: string }>(enumsCreator: () => T) {
    let enums = enumsCreator();
    …
}

const FolderVisibility = Enum(()=> 
{
    enum FolderVisibility {
        PUBLIC ='public',
        PRIVATE=  'private'
    }
    return FolderVisibility;
});