🪟 Windows TippsModify Windows Support Phone Number with PowerShell(03.09.2026 um 00:00 Uhr)
🔧 AI Nachrichten Podcast: ChatGPT schwatzt Nutzern in Deutschland jetzt Werbung auf(28.08.2026 um 08:46 Uhr)
🪟 Windows TippsMicrosoft bringt Emoji 17.0 auf Windows 11(31.08.2026 um 08:16 Uhr)
🪟 Windows TippsModify Windows Support Phone Number with PowerShell(03.09.2026 um 00:00 Uhr)
🔧 AI Nachrichten Podcast: ChatGPT schwatzt Nutzern in Deutschland jetzt Werbung auf(28.08.2026 um 08:46 Uhr)
🪟 Windows TippsMicrosoft bringt Emoji 17.0 auf Windows 11(31.08.2026 um 08:16 Uhr)

🔧 Programmierung 🕛 vor 1 Monat 9 Min Lesezeit
0

Your Build Target Is Not an API Contract: Enforcing Baseline with TypeScript

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Vite 7 and later use was Baseline 2024 Newly Available.


  • for JavaScript built-ins such as Promise, Array, and Map.

  • Use . It removes TypeScript syntax but does not run type checking by itself.



    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:




    CODE
    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




    CODE
    {
    "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:




    CODE
    {
    "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:




    CODE
    /// <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:




    CODE
    // 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:




    CODE
    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:




    CODE
    npx tsc -p tsconfig.baseline.json






    The established APIs compile, while the APIs outside Widely Available are rejected:




    CODE
    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:




    CODE
    {
    "scripts": {
    "check:baseline": "tsc -p tsconfig.baseline.json"
    }
    }






    If your existing CI job already installs dependencies, adding this command may be enough:




    CODE
    npm run check:baseline






    A standalone GitHub Actions workflow looks like this:




    CODE
    # .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:




    CODE
    {
    "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:




    CODE
    npm install --save-dev @baseline-types/dom-2024






    Then use the cumulative 2024 targets:




    CODE
    {
    "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:




    CODE
    npm install core-js






    Load the runtime implementation:




    CODE
    import "core-js/proposals/promise-with-resolvers";






    Then add the matching audited declaration entry:




    CODE
    {
    "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:




    CODE
    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.

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
  • Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    1 Quelle
    Modify Windows Support Phone Number with PowerShell
    1 Quelle
    Die Zukunft des Einkaufens: Warum wir ein neues Kapitel aufschlagen (und wie du es mitschreiben kannst)
    1 Quelle
    ZDE Podcast 251: Wie sieht digitales Instore Marketing 2026 aus, Amit Chatterjee?