首页 > 解决方案 > 使用 Enum 填充字段的通用工厂

问题描述

我不知道如何让这个工厂createLetterMap为其实例生成默认值......

'如何遍历枚举'并不是真正的问题,因为我理解这是不可能的,因为类型在运行时不可用,但也许我错过了关于字符串枚举的一些东西?


enum Letter{
    A = "A",
    B = "B",
    E = "E",
    I = "I",

}
type Vowl = Letter.A | Letter.E | Letter.I

class LMAP{
    test(){}
}
function createLetterMap<T extends Letter>(){
    let lmapExtended = new LMAP() as LMAP & {
        [key in T]?:string
    };

    // ?? create default values for keys somehow ??

    return lmapExtended;
}

let vowlMap = createLetterMap<Vowl>()

vowlMap[Letter.E] = "Eat" // OK
// vowlMap[Letter.B] = "Bat" // Error! Good!

let defaultVal = vowlMap[Letter.A]; // undefined. Would like it to be populated.

更一般地说,我想使用字符串枚举的联合来生成键控对象,在这些对象中我可以使用枚举作为键来处理类似这样的情况:

fn(v:Vowl){

  ...

  letterMap[v].someVowlReleatedWork()

  ...

}

我已经探索了替代方案,只是使用~工作~的实际地图,但如果我能正确指定类型,似乎有一种方法可以让事情变得更干净......

我想出的最好的方法是制作一个包含在联合类型中的额外枚举数组,并同时使用联合和工厂数组;类似下面的东西,看起来有点愚蠢:

...

let Vowls = [Letter.A,... ]
createLetterMap<Vowl>(Vowls)

标签: typescriptenumstypescript-generics

解决方案


您不能将类型定义用作值,因为它们在运行时被删除 -for(let key of keyof Vowl不起作用。

您可以将地图实现为一个类,或者如果您真的想在运行时提取键,您可以使用自定义转换器,例如ts-transformer-keys


enum Letter {
  A = "A",
  B = "B",
  E = "E",
  I = "I",

}
type Vowl = Letter.A | Letter.E | Letter.I

interface IMapper<T> { operation(value: T): void }

class VowlMapper implements IMapper<Vowl> {
  operation(vowel: Vowl) {
    console.log("VowlMapper: " + vowel);
  }
}

class LetterMap<T extends Letter> {

  private map: IMapper<T> & { [key in T]?: string };

  constructor(map: IMapper<T>) {
    this.map = map;
  }

  get(letter: T) {
    return this.map[letter] ?? letter;
  }

  set(letter: T, value: any) {
    this.map[letter] = value;
  }

  operation(value: T) {
    return this.map.operation(value);
  }

}

let vowlMap = new LetterMap(new VowlMapper())

vowlMap.set(Letter.E, "Eat");
// vowlMap.set(Letter.B, "Bat"); // Error! Good!

console.log(vowlMap.get(Letter.A))  // A
//console.log(vowlMap.get(Letter.B))  // error
console.log(vowlMap.get(Letter.E))  // Eat

vowlMap.operation(Letter.A); // VowlMapper: A 

查看操场示例


推荐阅读