Skip to content

Commit aba7ba5

Browse files
committed
feat: extract GMI calculation coefficients to named constants
- Add GMI_COEFFICIENTS constant with documented formula values - Replace magic numbers in a1cToGMI() and estimateGMI() - Improves maintainability and self-documenting code - References clinical formula sources in docs BREAKING CHANGE: None
1 parent fa12aff commit aba7ba5

File tree

2 files changed

+201
-8
lines changed

2 files changed

+201
-8
lines changed

src/constants.ts

Lines changed: 178 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const HOMA_IR_CUTOFFS = {
1515
VERY_SENSITIVE: 1,
1616
NORMAL: 2,
1717
EARLY_RESISTANCE: 2.9,
18-
}
18+
} as const
1919

2020

2121
/**
@@ -60,6 +60,26 @@ export const A1C_TO_EAG_MULTIPLIER = 28.7
6060
*/
6161
export const A1C_TO_EAG_CONSTANT = 46.7
6262

63+
/**
64+
* GMI (Glucose Management Indicator) calculation coefficients.
65+
* Used for estimating GMI from average glucose values.
66+
* @see https://diatribe.org/glucose-management-indicator-gmi
67+
*/
68+
export const GMI_COEFFICIENTS = {
69+
/** Slope for mmol/L to GMI conversion */
70+
MMOL_L_SLOPE: 1.57,
71+
/** Intercept for mmol/L to GMI conversion */
72+
MMOL_L_INTERCEPT: 3.5,
73+
/** Slope for mg/dL to GMI conversion */
74+
MG_DL_SLOPE: 0.03,
75+
/** Intercept for mg/dL to GMI conversion */
76+
MG_DL_INTERCEPT: 2.4,
77+
/** Slope for A1C to GMI conversion */
78+
A1C_SLOPE: 0.02392,
79+
/** Intercept for A1C to GMI conversion */
80+
A1C_INTERCEPT: 3.31,
81+
} as const
82+
6383
/**
6484
* Clinical conversion factor between mg/dL and mmol/L.
6585
* Used for unit conversion in all clinical analytics.
@@ -104,7 +124,7 @@ export const GLUCOSE_ZONE_COLORS = {
104124
// Colors for trending normal up and down
105125
NORMAL_UP: GLUCOSE_COLOR_NORMAL_UP, // Lighter Green
106126
NORMAL_DOWN: GLUCOSE_COLOR_NORMAL_DOWN, // Darker Green
107-
}
127+
} as const
108128

109129
/**
110130
* Unicode arrows for glucose trend indication.
@@ -116,4 +136,159 @@ export const TREND_ARROWS = {
116136
FALLING: '↘',
117137
RAPIDRISE: '↑',
118138
RAPIDFALL: '↓',
119-
}
139+
} as const
140+
141+
// ============================================================================
142+
// Enhanced Time-in-Range (TIR) Constants
143+
// Per International Consensus on Time in Range (Battelino et al. 2019)
144+
// ============================================================================
145+
146+
/**
147+
* Level 2 hypoglycemia threshold (mg/dL).
148+
* Readings below this value indicate clinically significant hypoglycemia.
149+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
150+
*/
151+
export const TIR_VERY_LOW_THRESHOLD_MGDL = 54
152+
153+
/**
154+
* Level 1 hypoglycemia threshold (mg/dL).
155+
* Target range begins at this value.
156+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
157+
*/
158+
export const TIR_LOW_THRESHOLD_MGDL = 70
159+
160+
/**
161+
* Level 1 hyperglycemia threshold (mg/dL).
162+
* Target range ends at this value.
163+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
164+
*/
165+
export const TIR_HIGH_THRESHOLD_MGDL = 180
166+
167+
/**
168+
* Level 2 hyperglycemia threshold (mg/dL).
169+
* Readings above this value indicate clinically significant hyperglycemia.
170+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
171+
*/
172+
export const TIR_VERY_HIGH_THRESHOLD_MGDL = 250
173+
174+
/**
175+
* Level 2 hypoglycemia threshold (mmol/L).
176+
* Readings below this value indicate clinically significant hypoglycemia.
177+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
178+
*/
179+
export const TIR_VERY_LOW_THRESHOLD_MMOLL = 3.0
180+
181+
/**
182+
* Level 1 hypoglycemia threshold (mmol/L).
183+
* Target range begins at this value.
184+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
185+
*/
186+
export const TIR_LOW_THRESHOLD_MMOLL = 3.9
187+
188+
/**
189+
* Level 1 hyperglycemia threshold (mmol/L).
190+
* Target range ends at this value.
191+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
192+
*/
193+
export const TIR_HIGH_THRESHOLD_MMOLL = 10.0
194+
195+
/**
196+
* Level 2 hyperglycemia threshold (mmol/L).
197+
* Readings above this value indicate clinically significant hyperglycemia.
198+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
199+
*/
200+
export const TIR_VERY_HIGH_THRESHOLD_MMOLL = 13.9
201+
202+
// ============================================================================
203+
// Pregnancy-Specific TIR Constants
204+
// Per ADA Standards of Care in Diabetes (2024, 2025)
205+
// ============================================================================
206+
207+
/**
208+
* Lower bound of target glucose range during pregnancy (mg/dL).
209+
* Applies to Type 1, Type 2, and gestational diabetes.
210+
* @see {@link https://diabetesjournals.org/care/article/47/Supplement_1/S282 | ADA Standards of Care (2024)}
211+
*/
212+
export const PREGNANCY_TARGET_LOW_MGDL = 63
213+
214+
/**
215+
* Upper bound of target glucose range during pregnancy (mg/dL).
216+
* Applies to Type 1, Type 2, and gestational diabetes.
217+
* @see {@link https://diabetesjournals.org/care/article/47/Supplement_1/S282 | ADA Standards of Care (2024)}
218+
*/
219+
export const PREGNANCY_TARGET_HIGH_MGDL = 140
220+
221+
/**
222+
* Lower bound of target glucose range during pregnancy (mmol/L).
223+
* Applies to Type 1, Type 2, and gestational diabetes.
224+
* @see {@link https://diabetesjournals.org/care/article/47/Supplement_1/S282 | ADA Standards of Care (2024)}
225+
*/
226+
export const PREGNANCY_TARGET_LOW_MMOLL = 3.5
227+
228+
/**
229+
* Upper bound of target glucose range during pregnancy (mmol/L).
230+
* Applies to Type 1, Type 2, and gestational diabetes.
231+
* @see {@link https://diabetesjournals.org/care/article/47/Supplement_1/S282 | ADA Standards of Care (2024)}
232+
*/
233+
export const PREGNANCY_TARGET_HIGH_MMOLL = 7.8
234+
235+
// ============================================================================
236+
// Clinical TIR Goals (percentages)
237+
// Per International Consensus on Time in Range (Battelino et al. 2019)
238+
// ============================================================================
239+
240+
/**
241+
* Target percentage for time-in-range (70-180 mg/dL).
242+
* Clinical goal: ≥70% of readings in target range.
243+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
244+
*/
245+
export const TIR_GOAL_STANDARD = 70
246+
247+
/**
248+
* Maximum acceptable percentage for Level 1 hypoglycemia (54-69 mg/dL).
249+
* Clinical goal: <4% of readings in this range.
250+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
251+
*/
252+
export const TBR_LEVEL1_GOAL = 4
253+
254+
/**
255+
* Maximum acceptable percentage for Level 2 hypoglycemia (<54 mg/dL).
256+
* Clinical goal: <1% of readings in this range.
257+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
258+
*/
259+
export const TBR_LEVEL2_GOAL = 1
260+
261+
/**
262+
* Maximum acceptable percentage for Level 1 hyperglycemia (181-250 mg/dL).
263+
* Clinical goal: <25% of readings in this range.
264+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
265+
*/
266+
export const TAR_LEVEL1_GOAL = 25
267+
268+
/**
269+
* Maximum acceptable percentage for Level 2 hyperglycemia (>250 mg/dL).
270+
* Clinical goal: <5% of readings in this range.
271+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
272+
*/
273+
export const TAR_LEVEL2_GOAL = 5
274+
275+
/**
276+
* Target percentage for time-in-range for older/high-risk adults.
277+
* More lenient goal: ≥50% of readings in target range.
278+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
279+
*/
280+
export const TIR_GOAL_OLDER_ADULTS = 50
281+
282+
/**
283+
* Maximum acceptable percentage for Level 1 hypoglycemia for older/high-risk adults.
284+
* More stringent goal: <1% of readings in this range.
285+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
286+
*/
287+
export const TBR_LEVEL1_GOAL_OLDER_ADULTS = 1
288+
289+
/**
290+
* Maximum acceptable percentage for Level 2 hypoglycemia for older/high-risk adults.
291+
* More stringent goal: <0.5% of readings in this range.
292+
* @see {@link https://diabetesjournals.org/care/article/42/8/1593 | International Consensus on Time in Range (2019)}
293+
*/
294+
export const TBR_LEVEL2_GOAL_OLDER_ADULTS = 0.5

src/conversions.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import {
66
MGDL_MMOLL_CONVERSION,
77
MG_DL,
88
MMOL_L,
9+
GMI_COEFFICIENTS,
910
} from './constants'
10-
import { GlucoseUnit } from './types'
11-
import type { EstimateGMIOptions } from './types'
11+
import type { GlucoseUnit, EstimateGMIOptions, ConversionResult } from './types'
1212
import { isEstimateGMIOptions } from './guards'
1313
import { parseGlucoseString } from './glucose'
1414

@@ -73,7 +73,10 @@ export function estimateA1CFromAverage(
7373
* @see https://diatribe.org/glucose-management-indicator-gmi
7474
*/
7575
export function a1cToGMI(a1c: number): number {
76-
return +(3.31 + 0.02392 * a1c).toFixed(2)
76+
return +(
77+
GMI_COEFFICIENTS.A1C_INTERCEPT +
78+
GMI_COEFFICIENTS.A1C_SLOPE * a1c
79+
).toFixed(2)
7780
}
7881

7982
/**
@@ -114,7 +117,10 @@ export function estimateGMI(
114117
throw new Error('Glucose value must be a positive number.')
115118
}
116119

117-
const gmi = resolvedUnit === MMOL_L ? 1.57 * value + 3.5 : 0.03 * value + 2.4
120+
const gmi =
121+
resolvedUnit === MMOL_L
122+
? GMI_COEFFICIENTS.MMOL_L_SLOPE * value + GMI_COEFFICIENTS.MMOL_L_INTERCEPT
123+
: GMI_COEFFICIENTS.MG_DL_SLOPE * value + GMI_COEFFICIENTS.MG_DL_INTERCEPT
118124

119125
return parseFloat(gmi.toFixed(1))
120126
}
@@ -126,6 +132,12 @@ export function estimateGMI(
126132
* @returns Value in mmol/L
127133
* @throws {Error} If val is not a finite number or is negative/zero
128134
* @see https://www.diabetes.co.uk/diabetes_care/blood-sugar-conversion.html
135+
*
136+
* @example
137+
* ```typescript
138+
* const result = mgDlToMmolL(180)
139+
* console.log(result) // 10.0
140+
* ```
129141
*/
130142
export function mgDlToMmolL(val: number): number {
131143
if (!Number.isFinite(val) || val <= 0)
@@ -140,6 +152,12 @@ export function mgDlToMmolL(val: number): number {
140152
* @returns Value in mg/dL
141153
* @throws {Error} If val is not a finite number or is negative/zero
142154
* @see https://www.diabetes.co.uk/diabetes_care/blood-sugar-conversion.html
155+
*
156+
* @example
157+
* ```typescript
158+
* const result = mmolLToMgDl(5.5)
159+
* console.log(result) // 99
160+
* ```
143161
*/
144162
export function mmolLToMgDl(val: number): number {
145163
if (!Number.isFinite(val) || val <= 0)
@@ -163,7 +181,7 @@ export function convertGlucoseUnit({
163181
}: {
164182
value: number
165183
unit: GlucoseUnit
166-
}): { value: number; unit: GlucoseUnit } {
184+
}): ConversionResult {
167185
if (!Number.isFinite(value) || value <= 0)
168186
throw new Error('Invalid glucose value')
169187
if (![MG_DL, MMOL_L].includes(unit)) throw new Error('Invalid unit')

0 commit comments

Comments
 (0)