type docs javascript enums flowtype

javascript - docs - flow object



¿Cómo usar/definir enumeraciones con comprobación de tipo de flujo? (3)

Estoy tratando de migrar una base de código existente para usar Flow. Dado que este proyecto comenzó sin Flow, estoy usando un patrón JS bastante típico para las enumeraciones y demás.

Aquí hay algunas definiciones que quiero

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, ]

El flujo funciona bien hasta que importe este archivo y dice que necesito agregar anotaciones de tipo. Esto parece extraño. ¿Por qué debería tener que anotar objetos que son completamente estáticos y que se pueden inferir fácilmente?

¿Hay alguna forma que defina su tipo como "estático" o "literal"?

Entonces pienso en cómo voy a agregar anotaciones a esto. Mi primer pensamiento es solo {[key: string]: string} y Array<string> . El flujo funciona, pero me doy cuenta de que estas definiciones de tipo no tienen ningún valor. Entonces intento este otro enfoque:

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"

Y utilizo las anotaciones de tipo {[key: LoanStatusKeys]: LoanStatusValues} y Array<ActiveLoanStatus> . ¡Pero incluso estas anotaciones pierden el hecho de que esto es estático!

Simplemente parece tan extraño que tengo que escribir tanto código duplicado. Y luego, si quiero convertir solo a Flow, no puedo usar los tipos en JS. Por ejemplo, podría hacer esto:

if (defs.ACTIVE_LOAN_STATUS.indexOf(loan.status) !== -1) { }

Ahora, si quiero usar tipos de flujo, no puedo hacer nada como esto:

type ActiveLoanStatus = "current" | "due" | "overdue" | "pending_payment" if (loan.status isTypeOf ActiveLoanStatus) { }

Entonces, ¿cómo se supone que debo usar estas enumeraciones estáticas? ¡Debo estar haciendo esto mal!


Aquí está la manera más concisa de lograr esto:

const activeLoanStatuses = { current: ''current'', due: ''due'', overdue: ''overdue'', pending_payment: ''pending_payment'' }; const otherLoanStatuses = { pending: ''pending'', charged_off: ''charged_off'', voided: ''voided'', disputed: ''disputed'', refunded: ''refunded'', settled: ''settled'', }; type ActiveLoanStatus = $Keys<typeof activeLoanStatuses>; type LoanStatus = $Keys<typeof otherLoanStatuses> | ActiveLoanStatus; const activeLoanStatusesMap: { [key: LoanStatus]: ?ActiveLoanStatus} = activeLoanStatuses; if (activeLoanStatusesMap[loan.status]) { }


Para expresar una enumeración con flujo, puede usar la utilidad $Values junto con el tipo de objeto congelado:

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, ]

Esto funciona a partir de la versión 0.60.0 .


Si bien es increíblemente detallado y no escalable, esto se incluye en el caso de " Disjoint Unions " de Flow y se puede implementar utilizando === . Como se menciona en esa página, el Análisis de casos se realiza a través de ese operador, como lo hace el javascript con switch-case declaraciones de switch-case .

En su caso, eso equivale a:

switch(loan.status) { ''pending'': ''current'': ''due'': ''overdue'': ''pending_payment'': ''charged_off'': ''voided'': ''disputed'': ''refunded'': ''settled'': // your behavior here }

Como mencioné, esto es muy detallado en el código que utiliza sus tipos, pero para contrarrestarlo, tiene la ventaja de definir sus tipos sin crear un objeto repetitivo: simplemente defina sus opciones literales y únalas (su segunda implementación).

Esto tiene el inconveniente obvio de acoplar su definición de tipo con sus implementaciones de sus consumidores, así que use con precaución.