Raw phone numbers leaking will ruin your whole day

Published: (February 3, 2026 at 11:30 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

Introduction

Shipping phone masking sounds trivial… until you meet international formats, weird inputs, and that one QA test with +62 (812)-3456..7890. This TypeScript phone‑masking utility is built for that reality, follows GDPR and data‑protection standards, makes no locale assumptions, accepts strings or numbers, and safely normalizes whatever chaos you throw at it. No country rules, no phone‑metadata databases—just predictable masking that doesn’t fight you.

Default behavior

The default behavior is intentionally boring (in a good way): it masks everything except the last 4 digits.

maskPhone('1234567890')
// ******7890

maskPhone('+62 812 3456 7890')
// +*********7890

You don’t need to configure anything to get sane output—exactly how a utility like this should behave.

Configurable options

When you need control, the API stays flat and readable.

Show a few digits at the front

maskPhone('628123456789', { showFirst: 3, showLast: 2 })
// 628*******89

Preserve formatting for UI display

maskPhone('+1 (555) 123-4567', { preserveFormat: true })
// +* (***) ***-4567

No magic, no surprises. The function does exactly what the options say—nothing more, nothing less.

Custom mask

For the “I know what I’m doing” crowd, customMask overrides everything and gives you full control per character.

maskPhone('1234567890', {
  customMask: (char, idx) => (idx % 2 === 0 ? '*' : char),
})
// *2*4*6*8*0

Under the hood

The code stays tiny, dependency‑free, and aggressively defensive:

  • null values won’t crash it.
  • Absurd option values won’t leak data.
  • Long inputs won’t melt your logs.

It’s the kind of utility you drop into UI, analytics, or logging and then forget about—which is the highest compliment you can give masking code.

Installation

The code lives on GitHub, fully open, zero drama:

GitHub repository

Install it with your preferred package manager:

npm install @ekaone/mask-phone
# or
yarn add @ekaone/mask-phone
# or
pnpm add @ekaone/mask-phone

That’s it. No post‑install rituals, no peer‑dependency surprises, and no “why is this 3 MB?”.

Back to Blog

Related posts

Read more »

Next.js ConnectRPC Proxy Pattern

!Cover image for Next.js ConnectRPC Proxy Patternhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-...