我尝试迁移现有代码库以使用Flow。由于这个项目是在没有Flow的情况下开始的,所以我使用了非常典型的JS模式来实现枚举等。
以下是我想要的一些定义
export const LOAN_STATUS = {
PENDING: 'pending',
CURRENT: 'current',
DUE: 'due',
OVERDUE: 'overdue',
PENDING_PAYMENT: 'pending_payment',
CHARGED_OFF: 'charged_off',
VOIDED: 'voided',
DISPUTED: 'disputed',
REFUNDED: 'refunded',
SETTLED: 'settled',
}
export const ACTIVE_LOAN_STATUS = [
LOAN_STATUS.OVERDUE,
LOAN_STATUS.CURRENT,
LOAN_STATUS.DUE,
LOAN_STATUS.PENDING_PAYMENT,
]
Flow工作正常,直到我导入此文件,它说我需要添加类型注释。这看起来很奇怪 - 为什么我必须注释完全静态且易于推断的对象?
有没有办法将其类型定义为"静态"或"字面意思"?
然后我开始考虑如何为此添加注释。我的第一个想法只是{[key: string]: string}
和Array<string>
。 Flow有效,但我意识到这些类型定义完全没用。那么我尝试另一种方法:
type LoanStatusValues =
'pending' |
'current' |
'due' |
'overdue' |
'pending_payment' |
'charged_off' |
'voided' |
'disputed' |
'refunded' |
'settled'
type LoanStatusKeys =
'PENDING' |
'CURRENT' |
'DUE' |
'OVERDUE' |
'PENDING_PAYMENT' |
'CHARGED_OFF' |
'VOIDED' |
'DISPUTED' |
'REFUNDED' |
'SETTLED'
type ActiveLoanStatus =
"current" |
"due" |
"overdue" |
"pending_payment"
我使用了类型注释{[key: LoanStatusKeys]: LoanStatusValues}
和Array<ActiveLoanStatus>
。但即便是这些注释也忽略了这是静态的事实!
我似乎很奇怪,我必须编写这么多重复的代码。然后,如果我想转换为Flow,我实际上不能使用JS中的类型。例如,我可能会这样做:
if (defs.ACTIVE_LOAN_STATUS.indexOf(loan.status) !== -1) {
}
现在,如果我想使用Flow类型,我就不能做这样的事情:
type ActiveLoanStatus =
"current" |
"due" |
"overdue" |
"pending_payment"
if (loan.status isTypeOf ActiveLoanStatus) {
}
那么我应该如何使用这些静态枚举?我一定是做错了!
答案 0 :(得分:7)
要使用流表达枚举,可以将$Values实用程序与冻结对象类型结合使用:
export const LOAN_STATUS = Object.freeze({
PENDING: 'pending',
CURRENT: 'current',
DUE: 'due',
OVERDUE: 'overdue',
PENDING_PAYMENT: 'pending_payment',
CHARGED_OFF: 'charged_off',
VOIDED: 'voided',
DISPUTED: 'disputed',
REFUNDED: 'refunded',
SETTLED: 'settled',
});
type LoanStatus = $Values<typeof LOAN_STATUS>;
export const ACTIVE_LOAN_STATUS: LoanStatus[] = [
LOAN_STATUS.OVERDUE,
LOAN_STATUS.CURRENT,
LOAN_STATUS.DUE,
LOAN_STATUS.PENDING_PAYMENT,
]
这可以从0.60.0版本开始。
答案 1 :(得分:1)
虽然令人难以置信的冗长且不可扩展,但这属于Flow的“Disjoint Unions”案例,可以使用===
来实现。正如他们在该页面上提到的那样,案例分析是通过该运算符完成的,因为javascript自然会对switch-case
语句执行。
在您的情况下,这相当于:
switch(loan.status) {
'pending':
'current':
'due':
'overdue':
'pending_payment':
'charged_off':
'voided':
'disputed':
'refunded':
'settled':
// your behavior here
}
正如我所提到的,这在使用您的类型的代码中非常冗长,但为了解决这个问题,它可以在不创建样板对象的情况下定义类型 - 您只需定义文字选项并将它们合并在一起(第二个)实现)。
这有明显的缺点,即将您的类型定义与其消费者的实现相结合,因此请谨慎使用。