Vite 7 and later use was Baseline 2024 Newly Available.
for JavaScript built-ins such as
Promise, Array, and Map.Its build target tells the transformer which JavaScript syntax needs to be lowered. It does not automatically reject every API that falls outside the corresponding Baseline target, and it does not generally inject API polyfills.
TypeScript checks APIs through declaration files such as lib.esnext.d.ts and lib.dom.d.ts. Those files model a selected ECMAScript or web platform surface. They are not filtered by Baseline status.
Both tools are doing their intended jobs. The missing layer is a declaration set that represents the API policy we want to enforce.
Add a Baseline API check
Install TypeScript and the two generated declaration packages:
npm install --save-dev \
typescript@^7 \
typescript-baseline-lib \
@baseline-types/dom-widely-available
Commit the lockfile. The package versions determine the exact Baseline snapshots evaluated in CI.
Keep your existing build configuration and add a dedicated TypeScript project.
tsconfig.baseline.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"strict": true,
"noEmit": true,
"noLib": true,
"allowImportingTsExtensions": true,
"types": [
"typescript-baseline-lib",
"@baseline-types/dom-widely-available"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"**/vite-env.d.ts"
]
}
The important options are:
{
"compilerOptions": {
"noLib": true,
"types": [
"typescript-baseline-lib",
"@baseline-types/dom-widely-available"
]
}
}
noLib removes TypeScript's standard ES and DOM libraries. The types entries replace them with the Baseline-oriented declarations.
Do not combine this configuration with the standard es* libraries. Doing so would reintroduce the APIs the gate is intended to remove.
I also recommend leaving skipLibCheck disabled. Declaration conflicts are useful signals here, not noise to suppress.
Why this config does not extend the build config
Many frontend projects already declare compilerOptions.lib.
Combining an inherited lib with noLib: true produces a configuration error. A standalone file is therefore the safest copy-paste starting point.
For a larger codebase, extract options such as strict, jsx, paths, and module resolution into a shared config that contains neither lib nor types. The normal build and Baseline check can then extend that shared configuration independently.
If the project contains TSX, add src/**/*.tsx to include and copy its existing jsx option into the Baseline config.
Vite client declaration note
A typical Vite project contains:
/// <reference types="vite/client" />
Vite's client declarations include asset modules and environment types, but they can also reference Worker APIs. Worker declarations are outside the scope of the DOM package used here.
For a strict browser-only gate, exclude the existing vite-env.d.ts and declare only the asset types your application uses:
// src/baseline-env.d.ts
declare module "*.css";
declare module "*.svg" {
const url: string;
export default url;
}
declare module "*.png" {
const url: string;
export default url;
}
If your application uses import.meta.env, add only the required ImportMetaEnv declarations to the same file.
This avoids widening the Baseline type surface with unrelated Worker globals.
See what the gate catches
Add a mix of established and newer APIs:
const newestOdd = [2, 5, 8, 11].findLast(
(value) => value % 2 === 1,
);
const response = await fetch("https://example.com");
const observer = new ResizeObserver(() => {});
Promise.withResolvers<number>();
Array.fromAsync([1, 2, 3]);
new EyeDropper();
document.startViewTransition(() => {});
console.log(newestOdd, response.status, observer);
export {};
Run the dedicated check:
npx tsc -p tsconfig.baseline.json
The established APIs compile, while the APIs outside Widely Available are rejected:
error TS2550: Property 'withResolvers' does not exist on type 'PromiseConstructor'.
error TS2550: Property 'fromAsync' does not exist on type 'ArrayConstructor'.
error TS2304: Cannot find name 'EyeDropper'.
error TS2339: Property 'startViewTransition' does not exist on type 'Document'.
At the time of testing:
| API | Baseline status | Result |
|---|---|---|
Array.prototype.findLast() | Widely Available | Accepted |
fetch() | Widely Available | Accepted |
ResizeObserver | Widely Available | Accepted |
Promise.withResolvers() | 2024 Newly Available | Rejected |
Array.fromAsync() | 2024 Newly Available | Rejected |
EyeDropper | Limited availability | Rejected |
Document.startViewTransition() | 2025 Newly Available | Rejected |
Baseline status changes over time. These results were verified on July 23, 2026.
Turn it into a CI contract
Add a separate package script:
{
"scripts": {
"check:baseline": "tsc -p tsconfig.baseline.json"
}
}
If your existing CI job already installs dependencies, adding this command may be enough:
npm run check:baseline
A standalone GitHub Actions workflow looks like this:
# .github/workflows/baseline-types.yml
name: Baseline API check
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
baseline:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run check:baseline
For an existing project, introduce this as a separate check first. Review the initial findings, decide how each API should be handled, and only then make the check required.
That avoids turning a useful policy migration into an unexplained wall of CI failures.
Rolling target or fixed year?
A moving target is appropriate for applications that want to adopt APIs as they become Widely Available:
{
"compilerOptions": {
"types": [
"typescript-baseline-lib",
"@baseline-types/dom-widely-available"
]
}
}
The declaration set advances when the underlying compatibility data and packages are updated.
A fixed Baseline year is more suitable for a library contract, a long-lived release branch, or a product that updates its browser policy deliberately.
Install the matching DOM target:
npm install --save-dev @baseline-types/dom-2024
Then use the cumulative 2024 targets:
{
"compilerOptions": {
"noLib": true,
"types": [
"typescript-baseline-lib/year/2024",
"@baseline-types/dom-2024"
]
}
}
A year target contains APIs that became Baseline Newly Available by the end of that year. It is not the same as saying every API was already Widely Available during that year.
Do not combine a fixed year/* entry with the rolling root package.
Make polyfills explicit
Sometimes an API is outside the selected Baseline target, but your runtime intentionally provides it.
For example, core-js can provide Promise.withResolvers:
npm install core-js
Load the runtime implementation:
import "core-js/proposals/promise-with-resolvers";
Then add the matching audited declaration entry:
{
"compilerOptions": {
"noLib": true,
"types": [
"typescript-baseline-lib",
"typescript-baseline-lib/allow/promise-withresolvers",
"@baseline-types/dom-widely-available"
]
}
}
This permits only that API. The rest of the Baseline boundary remains unchanged.
The allow/* entry changes type availability only. It does not install or load a runtime polyfill.
That separation is intentional: the runtime implementation and the type-level exception should both be visible in review.
What this check does not guarantee
This is an API-surface gate, not a complete browser compatibility system.
It does not guarantee:
- That an API works without browser-specific bugs.
- That requirements such as HTTPS, permissions, or user activation are met.
- That your actual audience matches the Baseline browser population.
- That JavaScript syntax, CSS, or HTML features meet the same target.
- That dynamically accessed or deliberately untyped APIs will be detected.
The DOM declarations also preserve some supporting types to keep references valid. They should not be interpreted as a perfect rejection of every non-Baseline DOM symbol.
If your users include old embedded WebViews, managed enterprise browsers, or unusually long-lived devices, Baseline Widely Available may still be too broad. Browser analytics and runtime testing remain necessary.
For broader JavaScript checks, I also use generates its JavaScript declarations from the web-features compatibility dataset and TypeScript's own library declarations. The repository checks in its dataset snapshot, classification reports, declaration inventory, generated output, and audit results.
is currently awaiting more real-world feedback.
If you try the package, the most useful feedback is concrete:
- Which project and TypeScript version did you test?
- Which API did the gate catch?
- Was the result expected?
- Did a framework or ambient type package introduce a conflict?
- Could the check remain enabled in CI?
Try it on one browser-only package:
npm install --save-dev \
typescript@^7 \
typescript-baseline-lib \
@baseline-types/dom-widely-available
npx tsc -p tsconfig.baseline.json
Browser compatibility policies should not depend on every reviewer remembering the support status of every API.
A small, reproducible CI check is a better contract.
SOCIAL SHARE CARD GENERATOR