Miten saada VS Code/TypeScript-automaattitäydennys ilman kirjaston tuontia


Jos moduuli (esim. moment.js, knockout tai big.js) sisällytetään <script>-tagilla, esim.

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js">
</script>

jotka määrittelevät globaalin ominaisuuden (esim. moment, ko, Big jne.), kuinka voi käyttää/määritellä tyyppejä window- tai global-objektissa Typescriptissä.

Esimerkiksi

const x = moment()
const t = ko.observable()
const b = new Big()

Kuinka voi asettaa näiden globalien ympäristötyypin ilman, että koko moment.js -kirjastoa otetaan mukaan? Tavoitteena on saada oikein tyypitetyt globaaliviittaukset, joita voivat käyttää VS Code sekä tsc, ts-loader tai babel-typescript.

Tapauksessa moment tyypit ovat esillä kohdassa node_modules/moment/moment.d.ts, mutta muiden kirjastojen (esim. knockout tai big.js) osalta ne ovat kohdassa @types/[module]/index.d.ts.

Tuntuu siltä, että tämä olisi melko yleistä, mutta en ole nähnyt hyvää, toimivaa esimerkkiä siitä, miten tämän voisi toteuttaa.

Tässä on tsconfig:

{
    "compilerOptions": {
      "target": "ESNext",
      "moduleResolution": "node",
      "allowJs": true,
      "noEmit": true,
      "strict": false,
      "isolatedModules": false,
      "esModuleInterop": true,
      "noResolve": false,
      "baseUrl": ".",
      "paths": {
        "*": [
          "*",
          "js.packages/*"
        ]
      },
      "jsx": "preserve",
      "outDir": "dist/"
  },
  "include": [
    "js.packages/**/*.ts",
    "js.packages/**/*.tsx",
    "js.packages/@types/lib.d.ts",
  ],
  "files": [
    "services/app/src/entry.js"
  ],
  "exclude": [
    "node_modules"
  ]
}

Tässä on lib.d.ts

declare global {
  type Bigable = Big | string | number
  interface Window {
    Big: typeof import('big.js'),
    moment: typeof import('moment'),
    Sentry: typeof import('@sentry/browser'),
  }
}

ja näin kulutuksen tulisi toimia:

const v = new Big(1)
const m = moment()
const s = global.Sentry()
const o = ko.observable()

joka näyttää tältä VS Codessa (punainen alleviivaus osoittaa virheet):

Joten knockout toimii, koska @types/knockout/index.d.ts sisältää:

declare var ko: KnockoutStatic;
declare module "knockout" {
    export = ko;
}

kun taas olen samalla tavalla julistanut globaalin Big Window-rajapinnassa.

Valitettavasti Sentry ja moment (tässä esimerkissä) eivät näytä toimivan, eikä ole selvää, miksi tai mitä pitäisi tehdä tämän korjaamiseksi.

Vastaus #1

Sinulla on oikea ajatus, sinun täytyy käyttää import-tyyppiä saadaksesi tyypit importissa, sinun täytyy ilmoittaa muuttujat global-alueella. Ongelma on, että ilmoitat ominaisuudet Window-objektille. Vaikka mikä tahansa Window-objektille määritetty avain tulee globaaliksi muuttujaksi, TypeScript ei heijasta tätä. Voit ilmoittaa muuttujat suoraan globaalissa alueessa.

declare global {
  export var moment: typeof import('moment');
  export var Sentry: typeof import('@sentry/browser');
}

const m = moment()
Sentry.init({}) // Sentry() does not seem like it should work according to docs

Vastaus #2

Kysymys ei ole erityisen tarkka yhdelle alustatyypille, mutta kerron sinulle, miten saan moment-kirjaston toimimaan Angularissa.

Ensinnäkin, sinun ei pitäisi ladata skriptin URL-osoitteesta. Sinun tulisi suorittaa npm install moment laittaaksesi sen node_modules-kansioosi. Tämä varmistaa, että se pakataan sovelluksesi minifioituun versioon. Sinun ei tarvitse, mutta tämä on vahvasti suositeltavaa.

"scripts": [
          "node_modules/jquery/dist/jquery.slim.min.js",
          "node_modules/moment/moment.js",
           ...
        ]

Edellä mainitusta huolimatta, kun olet linkittänyt skriptin tsconfig-tiedostoosi (tai angular.json), käyttö on yhtä yksinkertaista kuin seuraava rivi tiedoston alussa:

import * as moment from 'moment';

Minulla on tapana käyttää tätä syntaksia useimmissa kirjastoissa, joilla on objekti, esim. shortid, linq ja lodash.

Muut kirjastot toimivat paremmin declare var -lauseiden kanssa. Esimerkiksi olen huomannut, että jQuery toimii paremmin sillä tavalla.

declare var $

Automaattinen täydennys

Jos etsit automaattista täydennystä, sinun on ladattava kirjastoille .d.ts-tiedosto. moment-npm-paketti sisältää sellaisen, mutta joillekin kirjastoille on asennettava toinen npm-paketti tätä varten (esim. @types/lodash, @types/jquery).

Visual Studio Autocomplete -toiminto perustuu .d.ts-tiedostoihin tyyppejä tunnistaakseen. Tämän ominaisuuden määritystä koskeva dokumentaatio löytyy täältä, ja sitä voi olla mahdollista määrittää (katso huomautus lähes alareunasta).