如果您有类似const的枚举
enum Color {
RED,
GREEN,
BLUE,
}
您可以编写一个帮助程序和一个switch语句,
function assertNever(x: never): never {
throw new Error(`Unexpected object: ${x}`)
}
function toString (key: Color): string {
switch (key) {
case Color.RED: return 'Red'
case Color.GREEN: return 'Green'
case Color.BLUE: return 'Blue'
default: return assertNever(key)
}
}
这样,如果我们曾经更改Color
,就必须更改我们的toString
实现。
但是,如果我走另一条路,
function fromString (key: string): Color {
switch (key) {
case 'Red': return Color.RED
case 'Green': return Color.GREEN
case 'Blue': return Color.BLUE
default: throw new Error(`${key} is not a Color`)
}
}
我的fromString实现可能与我的Color枚举不合时宜。
是否可以确保存在某种返回每种Color
的路径?有没有办法确保函数的范围是Color
?
答案 0 :(得分:2)
没有内置功能可以自动为您执行此操作。如果函数的实际返回类型比声明的返回类型更具体,则认为这不是错误...如果函数被声明为返回string
,但实际上总是返回特定的字符串{{1} }, 没关系。相反,这只是一个错误,在该函数中声明该函数返回特定的字符串"hello"
,但实际上返回的是常规的"hello"
。
一般而言,您可以做的一件事是让TypeScript推断函数的返回类型,然后使用编译时检查来确保它是您想要的。例如:
string
以上编译,但由于缺少// MutuallyExtends<T, U> only compiles if T extends U and U extends T
type MutuallyExtends<T extends U, U extends V, V=T> = true;
// note how the return type is not annotated
function fromString(key: string) {
switch (key) {
case 'Red': return Color.RED
case 'Green': return Color.GREEN
case 'Blue': return Color.BLUE
default: throw new Error(`${key} is not a Color`)
}
// the next line will error if not exhaustive:
type Exhaustive = MutuallyExtends<ReturnType<typeof fromString>, Color>
}
,以下内容会产生错误:
Color.BLUE
这当然是一种解决方法。但这可能会帮助您或其他人。希望有一定用处;祝你好运!
答案 1 :(得分:1)
有一种可能的解决方法,可能对您有用,不知道我是否正确理解您要实现的目标。
您可以使用所有可能的颜色字符串定义字符串文字类型。然后,当您更改枚举时,首先需要更改toString
函数,这将迫使您向颜色名称类型添加另一个值,因为您将没有新颜色的值。然后,这将破坏fromString
函数,因此您需要对其进行更新以使构建起作用。更改后的代码如下所示:
enum Color {
RED,
GREEN,
BLUE
}
type ColorName = 'Red' | 'Green' | 'Blue';
function assertNever(x: never): never {
throw new Error(`Unexpected object: ${x}`);
}
function toString (key: Color): ColorName {
switch (key) {
case Color.RED: return 'Red';
case Color.GREEN: return 'Green';
case Color.BLUE: return 'Blue';
default: return assertNever(key);
}
}
function assertNeverColor(x: never): never {
throw new Error(`${x} is not a Color`);
}
function fromString (key: ColorName): Color {
switch (key) {
case 'Red': return Color.RED;
case 'Green': return Color.GREEN;
case 'Blue': return Color.BLUE;
default: return assertNever(key);
}
}
答案 2 :(得分:1)
假设所有值都不同(否则很难映射),您可以执行从枚举到字符串的类型化映射,然后为其构建反向查找并以类型安全的方式使用它。
这是一个例子:
enum Color {
RED,
GREEN,
BLUE,
}
const ENUM_COLOR_TO_STRING: Record<Color, string> = {
[Color.RED]: 'Red',
[Color.GREEN]: 'Green',
[Color.BLUE]: 'Blue',
}
const COLORS: Color[] = Object.keys(ENUM_COLOR_TO_STRING) as unknown as Color[];
const STRING_COLOR_TO_ENUM: Record<string, Color> = COLORS.reduce<any>((acc, colorEnum) => {
const colorValue = ENUM_COLOR_TO_STRING[colorEnum]
acc[colorValue] = colorEnum;
return acc
}, {})
function fromString(key: string): Color {
const color: Color | undefined = STRING_COLOR_TO_ENUM[key];
if (!color) {
throw new Error(`${key} is not a Color`)
}
return color
}
Typescript Playground 上的现场演示