typescript - In typescript, is there a way to ensure that a function's return type is exhaustive?
问题描述
If you have a const enum like
enum Color {
RED,
GREEN,
BLUE,
}
You can write a helper and a switch statement,
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)
}
}
such that if we ever change Color
, we must change our toString
implementation.
However, if I go the other way,
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`)
}
}
It is possible that my fromString implememtation may get out of date with my Color enum.
Is there a way to ensure that there exists some path that returns each kind of Color
? Is there are way to ensure that the range of the function is Color
?
解决方案
没有内置功能会自动为您强制执行此操作。函数的实际返回类型比声明的返回类型更具体不被认为是错误...如果函数被声明为返回 astring
但实际上总是返回特定的 string "hello"
,那很好。做相反的事情只是一个错误,其中函数被声明为返回特定的字符串"hello"
,但实际上返回了一个 general string
。
一般来说,你可以做的一件事是让 TypeScript 推断函数的返回类型,然后使用编译时检查来确保它是你认为的那样。例如:
// 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
缺少:
function fromString(key: string) {
switch (key) {
case 'Red': return Color.RED
case 'Green': return Color.GREEN
default: throw new Error(`${key} is not a Color`)
}
type Exhaustive = MutuallyExtends<ReturnType<typeof fromString>, Color> // error!
// Color does not satisfy constraint Color.RED | Color.GREEN ---> ~~~~~
}
当然,这是一种解决方法。但也许它会帮助你或其他人。希望有一些用处;祝你好运!
推荐阅读
- java - 我收到异常错误:线程“main”中的异常 java.lang.ArrayIndexOutOfBoundsException: 6
- c - Fluidsynth - 如何调制/操纵来自不同 MIDI 通道的音频
- c# - 错误:sharepoint 中的“用户不存在或不是唯一的”使用 CSOM 添加用户
- string - 字符串未被识别为有效的布尔值。在 mvc5 中显示 @using 在剃刀中的错误
- c - 用于将文本转换为摩尔斯电码的 C 函数
- spring - Graphql依赖收敛问题
- aws-amplify - 为什么我使用 iam 进行身份验证时无法读取关系数据,但通过 cognito 用户池进行身份验证时可以读取
- shopware - 一对多关联的 Shopware 5 扩展问题
- java - 从 webview 重定向到 android 应用程序
- javascript - 如何将提交文本框中的值连接到 url API 调用中?