typescript 47 lines · 9 steps

Parsing a user-agent string with ordered rules

Ordered regex tables and a shared matcher turn a raw user-agent string into structured browser, OS, and device info.

Explained by highlit
1interface UserAgentInfo {
2 browser: { name: string; version: string };
3 os: { name: string; version: string };
4 device: 'mobile' | 'tablet' | 'desktop';
5}
6 
7const BROWSER_RULES: Array<[RegExp, string]> = [
8 [/Edg\/([\d.]+)/, 'Edge'],
9 [/OPR\/([\d.]+)/, 'Opera'],
10 [/Firefox\/([\d.]+)/, 'Firefox'],
11 [/Chrome\/([\d.]+)/, 'Chrome'],
12 [/Version\/([\d.]+).*Safari/, 'Safari'],
13 [/MSIE ([\d.]+)|rv:([\d.]+)\) like Gecko/, 'Internet Explorer'],
14];
15 
16const OS_RULES: Array<[RegExp, string]> = [
17 [/Windows NT ([\d.]+)/, 'Windows'],
18 [/Mac OS X ([\d_.]+)/, 'macOS'],
19 [/Android ([\d.]+)/, 'Android'],
20 [/(?:iPhone|iPad); CPU (?:iPhone )?OS ([\d_]+)/, 'iOS'],
21 [/Linux/, 'Linux'],
22];
23 
24function matchRule(ua: string, rules: Array<[RegExp, string]>) {
25 for (const [pattern, name] of rules) {
26 const m = ua.match(pattern);
27 if (m) {
28 const version = (m[1] ?? m[2] ?? '').replace(/_/g, '.');
29 return { name, version };
30 }
31 }
32 return { name: 'Unknown', version: '' };
33}
34 
35export function parseUserAgent(ua: string): UserAgentInfo {
36 const browser = matchRule(ua, BROWSER_RULES);
37 const os = matchRule(ua, OS_RULES);
38 
39 let device: UserAgentInfo['device'] = 'desktop';
40 if (/iPad|Tablet|(?=.*Android)(?!.*Mobile)/.test(ua)) {
41 device = 'tablet';
42 } else if (/Mobi|iPhone|Android.*Mobile/.test(ua)) {
43 device = 'mobile';
44 }
45 
46 return { browser, os, device };
47}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Ordering rules from most-specific to most-generic prevents broad patterns from swallowing narrower matches.
  2. 2A single generic matcher keeps browser and OS detection consistent by reusing the same lookup logic.
  3. 3Deriving a union type from an interface field keeps assignable values in lockstep with the contract.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Parsing a user-agent string with ordered rules — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code