惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threat Research - Cisco Blogs
A
Arctic Wolf
S
Securelist
O
OpenAI News
T
Threatpost
Forbes - Security
Forbes - Security
N
News and Events Feed by Topic
S
Secure Thoughts
H
Heimdal Security Blog
S
Security Affairs
P
Privacy International News Feed
C
Cisco Blogs
C
CERT Recently Published Vulnerability Notes
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Palo Alto Networks Blog
S
Security @ Cisco Blogs
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
T
Tailwind CSS Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hacker News: Ask HN
Hacker News: Ask HN
T
Troy Hunt's Blog
S
SegmentFault 最新的问题
腾讯CDC
V
Visual Studio Blog
Last Week in AI
Last Week in AI
H
Hacker News: Front Page
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Project Zero
Project Zero
WordPress大学
WordPress大学
NISL@THU
NISL@THU
博客园 - 【当耐特】
博客园 - Franky
Webroot Blog
Webroot Blog
博客园_首页
T
Tenable Blog
雷峰网
雷峰网
Google Online Security Blog
Google Online Security Blog
阮一峰的网络日志
阮一峰的网络日志
V2EX - 技术
V2EX - 技术
Recent Commits to openclaw:main
Recent Commits to openclaw:main
L
Lohrmann on Cybersecurity
The Hacker News
The Hacker News

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
as const Is the Best Single Feature TypeScript Has Shipped in 5 Years
Gabriel Anha · 2026-05-05 · via DEV Community

You add a new status to your app. The string "archived" goes
into a constant array at the top of the file, and a switch
statement in the reducer handles the new case. CI is green. You
ship.

Two days later a teammate adds "deleted" to the array and
forgets the reducer. The compiler does not flag it. The status
list is typed as string[]. The reducer parameter is typed as
string. Every status in the world satisfies that signature.
The bug ships behind a feature flag. Nobody catches it for a
week, until a customer ticket arrives asking why deleted items
still appear in the active list.

That bug is one keyword away from impossible. The keyword is
as const. It landed in TypeScript 3.4 in early 2019, and
I'll argue it has quietly out-earned every feature the
TypeScript team has shipped since. Most codebases use it for
one of its four jobs and miss the other three.

What as const actually does

as const is a type assertion that asks the compiler for the
narrowest possible type of the expression in front of it.
Strings stay as their literal value, not string. Numbers stay
as their literal value, not number. Arrays become readonly
tuples, not arrays. Object properties become readonly with
their literal types, not widened.

Here is the entire mental model in one snippet.

const a = ["click", "key"];
// a: string[]

const b = ["click", "key"] as const;
// b: readonly ["click", "key"]

const c = { kind: "click", x: 12 };
// c: { kind: string; x: number }

const d = { kind: "click", x: 12 } as const;
// d: { readonly kind: "click"; readonly x: 12 }

Enter fullscreen mode Exit fullscreen mode

That is it. Everything below is a pattern that falls out of the
same idea once you start composing it with the rest of the type
system.

Pattern 1: literal-type tuples instead of widened arrays

The most visible win is in fixed-shape tuples. A coordinate
pair, a key-value pair, a [ok, value] result. Without
as const, the array is widened to a homogeneous array type
and the positional information is lost.

function origin() {
  return [0, 0];
}
// returns: number[]

function originConst() {
  return [0, 0] as const;
}
// returns: readonly [0, 0]

Enter fullscreen mode Exit fullscreen mode

The first version lets a caller pass the result anywhere a
number[] is expected. The second version is a tuple of length
two with two literal zeroes, which is what the function
actually returns. Destructuring is sharper too: with the const
version, the compiler knows the first element is 0 and the
second element is 0, not just two unrelated numbers.

The pattern matters most for return values that callers will
destructure or splat. The useState shape from React is a
tuple, and every custom hook that wraps it has to remember to
return [value, setter] as const. Forget the assertion and
callers see (StateType | SetterType)[]. Type narrowing dies
at the boundary.

Pattern 2: const-enum replacement that stays serialisable

TypeScript enums have aged badly. They emit runtime objects
with reverse mappings nobody uses, they do not tree-shake well
in some configurations, const enum is broken under
isolated-modules and is now flagged in the official
handbook

as something to avoid in libraries. The Bun team has publicly
discouraged TypeScript enums in favour of as const objects.
Most modern codebases have moved on.

The replacement is a frozen object plus as const.

const Status = {
  Pending: "pending",
  Active: "active",
  Archived: "archived",
  Deleted: "deleted",
} as const;

type Status = (typeof Status)[keyof typeof Status];
// "pending" | "active" | "archived" | "deleted"

function setStatus(s: Status): void {
  // ...
}

setStatus(Status.Active);     // ok
setStatus("active");          // ok — Status is the union too
setStatus("typo");            // error

Enter fullscreen mode Exit fullscreen mode

The runtime value is a plain object. The keys are usable as
named constants (Status.Active). The type Status is the
union of all the values. JSON serialisation is automatic — the
values are real strings. Tree-shaking is whatever your bundler
does with object property access, which is fine in every modern
toolchain.

The Status type expression deserves a closer look because it
shows up in the next two patterns as well.

typeof Status                // the type of the object itself
keyof typeof Status          // "Pending" | "Active" | ...
(typeof Status)[keyof typeof Status]  // values: "pending" | "active" | ...

Enter fullscreen mode Exit fullscreen mode

The chain reads as: take the type of the object, take its keys,
index the object by those keys, and you get the union of value
types. The whole expression is a derivation. There is no
hand-written type Status = "pending" | "active" | ... line
that has to be kept in sync with the object. Add a key, the
type updates.

Pattern 3: deep-readonly via Readonly<typeof x>

Once a value is frozen with as const, the type already has
readonly markers on every property. That makes the structural
shape immutable to the type checker for free.

const config = {
  retries: 3,
  timeout: 5_000,
  endpoints: {
    auth: "/v1/auth",
    users: "/v1/users",
  },
} as const;

config.retries = 5;
// error: Cannot assign to 'retries' because it is a
// read-only property.

config.endpoints.auth = "/v2/auth";
// error: same.

Enter fullscreen mode Exit fullscreen mode

The as const recurses into the object literal. Every
property, at every depth, picks up readonly and a literal
type. You do not need a separate Readonly<T> wrapper for
shallow cases. For cases where you have a non-const value and
want a readonly view of its type, Readonly<typeof x> is the
shorthand, but the more interesting use is to derive the
literal-typed value type from the const expression and then
hand it around as a parameter type.

type Config = typeof config;
// readonly { retries: 3; timeout: 5000;
//   endpoints: readonly { auth: "/v1/auth";
//                         users: "/v1/users" } }

function withConfig(c: Config): void {
  // ...
}

Enter fullscreen mode Exit fullscreen mode

Callers cannot synthesise a fake Config with the wrong
endpoint string. The type carries the values, not just the
shape.

Pattern 4: deriving a union from a constant

This is the one that is worth showing side by side, because it
is the pattern that replaces the most hand-written code in the
average codebase.

The hand-written version. Keep two things in sync, or the
runtime and the type lie to each other.

const STATUSES = ["pending", "active", "archived", "deleted"];
type Status = "pending" | "active" | "archived" | "deleted";

function isStatus(s: string): s is Status {
  return STATUSES.includes(s);
}

Enter fullscreen mode Exit fullscreen mode

The as const-derived version. Same name, second take — one
source of truth, the type falls out.

const STATUSES = [
  "pending",
  "active",
  "archived",
  "deleted",
] as const;

type Status = (typeof STATUSES)[number];
// "pending" | "active" | "archived" | "deleted"

function isStatus(s: string): s is Status {
  return (STATUSES as readonly string[]).includes(s);
}

Enter fullscreen mode Exit fullscreen mode

The cast on STATUSES inside isStatus is there for a real
reason. After as const, STATUSES has type
readonly ["pending", "active", "archived", "deleted"] and
Array#includes types its argument as the element union. Pass
in an arbitrary string and TypeScript raises TS2345 because
string is wider than that union. Widening the array back to
readonly string[] for the call lets includes accept any
string, which is exactly what a guard wants. The function still
returns s is Status, so the type narrowing on the caller side
is unaffected.

The runtime array is the source of truth. The type is a
projection. Add "banned" to the array, the type updates,
every switch statement that exhausts Status flags as
non-exhaustive. The compiler does the bookkeeping a careful
human used to do.

(typeof STATUSES)[number] is the readable form of "index this
tuple type by any numeric position." Since every position holds
a literal string, the resulting type is the union of those
strings. The same idiom works for any tuple of HTTP methods,
supported locales, or feature flags.

The reducer for our opening bug becomes exhaustive by force.

function reduce(s: Status): string {
  switch (s) {
    case "pending":  return "Pending review";
    case "active":   return "In use";
    case "archived": return "Hidden";
    case "deleted":  return "Gone";
  }
}

Enter fullscreen mode Exit fullscreen mode

If you delete a case the function fails to compile, because the
switch returns string | undefined and the signature
promises string (under strict or noImplicitReturns; on a
permissive tsconfig the missing-case error goes silent). Add
"banned" to the array, the same function fails again until
you handle it. The bug from the lead paragraph cannot ship.

The one sharp edge

as const does not deep-recurse into nested arrays the way
people expect when the array is built dynamically. The literal
inference works on the syntactic shape at the point the
assertion is applied. Build the array elsewhere and pass it
through, and the inner types widen.

const inner = [1, 2, 3];
const outer = [inner, inner] as const;
// readonly [number[], number[]]
// not: readonly [readonly [1, 2, 3], readonly [1, 2, 3]]

Enter fullscreen mode Exit fullscreen mode

The fix is to apply as const at the deepest point, not the
outermost.

const inner = [1, 2, 3] as const;
const outer = [inner, inner] as const;
// readonly [readonly [1, 2, 3], readonly [1, 2, 3]]

Enter fullscreen mode Exit fullscreen mode

For dynamically built shapes, you need a helper. The standard
trick is a generic that re-asserts on each level.

type DeepReadonly<T> = T extends (infer U)[]
  ? readonly DeepReadonly<U>[]
  : T extends object
    ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
    : T;

Enter fullscreen mode Exit fullscreen mode

Most codebases never need it. The flat case covers eighty
percent of what as const is for. When you do need it, the
mapped type above is the canonical form.

Why this one keyword wins

Look at what it replaces. Hand-maintained string union types
that drift from their runtime constants. Enums that emit
unwanted runtime baggage. Tuples that widen into arrays the
moment they leave a function. Configuration objects that the
compiler will let you mutate at runtime because nobody wrote
Readonly everywhere. The hand-rolled isStatus guard that is
out of date the day you add a status.

as const is two tokens. It costs nothing at runtime. It
removes a category of bug that grows with every new constant
you add to the codebase. There is no other TypeScript feature
in the last five years that pays back this much from this
small a footprint.

The next time you write a STATUSES or ROLES array, or an
enum-like object, end the literal with as const. Add
type X = (typeof X)[number] for arrays or
type X = (typeof X)[keyof typeof X] for objects (the type X
and the const X share the name; TypeScript keeps them in
separate namespaces). Delete the hand-written union you would
have written underneath. The codebase gets two lines shorter
and the bug surface gets a lot smaller.


If this was useful

as const is one of the patterns TypeScript Essentials
unpacks alongside the day-to-day machinery — narrowing, modules,
async, the type-system features that show up in every working
codebase. If the four patterns above clicked and you want the
same depth of treatment for the rest of TypeScript's daily
surface area, that is the book. The TypeScript Type System
picks up where this post ends, with the conditional types,
mapped types, and infer patterns that compose with as const
into library-grade types.

If you are coming from JVM languages, Kotlin and Java to
TypeScript
makes the bridge into structural typing. If you are
coming from PHP 8+, PHP to TypeScript covers the same ground
from the other side. TypeScript in Production covers the
build, monorepo, and dual-publish concerns the type system
itself does not touch.

The five-book set:

  • TypeScript Essentials — From Working Developer to Confident TS, Across Node, Bun, Deno, and the Browser — entry point: amazon.com/dp/B0GZB7QRW3
  • The TypeScript Type System — From Generics to DSL-Level Types — deep dive: amazon.com/dp/B0GZB86QYW
  • Kotlin and Java to TypeScript — A Bridge for JVM Developers — bridge for JVM devs: amazon.com/dp/B0GZB2333H
  • PHP to TypeScript — A Bridge for Modern PHP 8+ Developers — bridge for PHP devs: amazon.com/dp/B0GZBD5HMF
  • TypeScript in Production — Tooling, Build, and Library Authoring Across Runtimes — production layer: amazon.com/dp/B0GZB7F471

All five books ship in ebook, paperback, and hardcover.

The TypeScript Library — the 5-book collection