A TypeScript hozzáadása egy JavaScript-projekthez

Szeretek kódot írni. És nagyon jó akarok lenni benne. De valahogy a JavaScript írása soha nem volt az erős választásom.

Bármennyire is gyakoroltam, ugyanazok a hibák folyamatosan megjelentek a produkcióban: cannot read property of undefinedkivételek, a híres [Object object]karakterlánc és még a függvényhívások is érvénytelen számú paraméterrel.

Sőt, a legtöbb kódbázis, amelyen dolgoztam, valóban nagy JavaScript volt. Tehát itt van egy szép ábra arról, hogy milyen érzés voltam én lenni:

Ebben a bejegyzésben elkerülöm annak magyarázatát, hogy a TypeScript miért fantasztikus (és így van), és összpontosítok azokra a feladatokra, amelyeket teljesítenie kell, ha át akarja helyezni a vanília JavaScript projektjét egy vegyes TypeScript projektbe.

A bejegyzés végére boldogabb ember leszel, és válaszolni tudsz a következő kérdésekre:

  • Hogyan adhatok típusokat a JavaScript-projektemhez?
  • Mi a TypeScript?
  • Hogyan használhatom a TypeScript-et egy JavaScript-projektben?
  • Milyen lépésekkel lehet átalakítani egy JavaScript alkalmazást a TypeScript támogatására?
  • Hogyan tudok gondoskodni az összeállításról és a csomagolásról?
  • Hogyan tudok vigyázni a szöszölésre?
  • Hogyan „adhatom el” a TypeScript-et a szervezetemnek és a fejlesztőknek?

Hogyan adhatok típusokat a JavaScript-projektemhez?

A vanília JavaScript jelenleg nem támogatja a típusokat, ezért ehhez valamilyen absztrakcióra van szükségünk a JavaScript tetején.

Néhány gyakori absztrakciók használata Facebook statikus típus-ellenőrző hívott flowés a Microsoft nyelv úgynevezett: typescript.

Ez a blogbejegyzés megvizsgálja a TypeScript használatát és hozzáadását a JavaScript-projektjéhez.

Mi az a gépírás?

A TypeScript egy tipikus JavaScript-készlet, amely egyszerű JavaScript-re áll össze.

A TypeScript néhány részből áll. Az első a TypeScript nyelv - ez egy új nyelv, amely az összes JavaScript funkciót tartalmazza. További információkért tekintse meg a specifikációkat.

A második a TypeScript fordító tsc(a type system engine), amely egy fordító motor, amely ts fájlokat épít és js fájlokat hoz létre.

Helló világ a TypeScript-ben

Például ezeket a lépéseket kell tennie az első TypeScript alkalmazás megírásához:

  1. telepítse a TypeScript-et npm i typescript
  2. hozz létre egy nevű mappát exampleés CD-t (a terminálodban)
  3. nevű fájlt hozhat létre hello.world.ts
  4. írja be a következő kódot:
const firstWords:string = "hello world" console.info(firstWords); 

majd mentse el.

5. futtassa a tscparancsot a TypeScript fordító futtatásához az aktuális mappában

6. vedd észre, hogy van egy hello.jsfájlod, amelyet most futtathatsz :)

7. futás node ./hello.js

Hogyan használhatom a TypeScript-et egy JavaScript-projektben?

Pár stratégia létezik ennek a "migrációnak" (vállalat és kód szerint). Az alábbiakban felsoroltam őket "költségük" és az általuk nyújtott érték alapján.

Azt javaslom, hogy kezdje az "alkalmazás TS támogatásával", és lépjen tovább, miután bebizonyította az értéket a fejlesztői csapat számára.

A "kis lépés az ember számára" megközelítés - TS támogatás hozzáadása a meglévő alkalmazásokhoz

Első javaslatom az, hogy hozzon létre egy keveréket a két nyelvből egyetlen projektben, majd írja be az összes „jövő” kódot a TypeScript-be.

Két nyelv kombinációja egyetlen projektben eleinte elég borzasztóan hangzik, de elég jól működik, mivel a TS fokozatos használatra készült. Eleinte ugyanúgy használható, mint JS .ts fájlokkal és furcsa import sorokkal.

Ebben a stratégiában összeállítjuk az áttelepített TypeScript fájlokat, és csak átmásoljuk a JavaScript fájlokat egy kimeneti mappába.

A megközelítés óriási előnye, hogy fokozatos tanulási görbét tesz lehetővé a fejlesztői csapat számára (és az Ön számára is) a nyelvvel és annak jellemzőivel. Ezenkívül gyakorlati tapasztalatokat és betekintést nyújt előnyeibe és hátrányaiba.

Nagyon ajánlom, hogy induljon el ettől a lépéstől, majd ismételje meg a csapatával, mielőtt továbblép. A gyors „hogyan kell ezt megtenni”, görgessen lefelé The steps to convert a javascript application to support typescriptrészig.

Nyitott üzleti megközelítés - TS támogatás hozzáadása a meglévő könyvtárakhoz.

Miután gyakorlott tapasztalataid vannak a TS-sel kapcsolatban, és a fejlesztői csapat egyetért azzal, hogy érdemes továbblépni, javaslom a házon belüli könyvtárak és modulok átalakítását a TS támogatására.

Ez kétféle módon történhet:

Az első módszer a deklarációs fájlok használatát jelenti. A d.tsfájlok egyszerű hozzáadása segít a TS fordítónak a meglévő JavaScript kód ellenőrzésében, és automatikus kiegészítést nyújt az IDE-ben.

Ez a "legolcsóbb" opció, mivel egyáltalán nem igényel semmilyen kódváltást a könyvtárban. Ezenkívül maximális teljesítményt és típusú támogatást nyújt a jövőbeli kódban.

A második módszer a TypeScript teljes újraírása, ami időigényes és hibára hajlamos lehet. Nem tanácsolom ellene, hacsak nem bizonyítja, hogy a ROI méltó a csapatához.

A csontváz - lépés a jövő felé

Feltételezem, hogy a legtöbb fejlesztő "lusta", és általában egy csontvázról történő másolással kezdik az alkalmazást (amely általában naplózást, mutatókat, konfigurációt stb. Tartalmaz).

Ez a lépés segít eligazodni a fényes jövőben, létrehozva egy "hivatalos" csontvázat a vállalat számára. 100% TS lesz, és megszünteti a régi JS csontvázat, ha van ilyen.

Ez a gépírás-csomópont-indító egy nagyon jó első projekt, amellyel kezdeni lehet.

Minden a megközelítésben - Teljes kódbázis konvertálása JS-ből TS-be

Ez az opció teljes átírást igényel a JavaScript-kódról a TypeScript-re.

Azt javaslom, hogy ezt tegye a TS áttelepítési folyamatának utolsó lépéseként, mivel teljes alkalmazás-átírást, valamint a TypeScript és a szolgáltatásainak mély ismeretét igényli.

Ilyen átírást (ez hosszú folyamat) a következő módon végezhet:

  1. Adja meg az üzleti üzleti logika, az API és a HTTP egyértelmű típusait
  2. Használjon @typescsomagokat a könyvtár összes könyvtárához package.json. Az ottani könyvtárak többsége támogatja a TS-t, és ebben a folyamatban azt javaslom, hogy egyesével költöztesse őket (csak hozzáadva @types/a package.jsonfájljához).
  3. Konvertálja az alkalmazás logikai összetevőit fontosságuk szerinti sorrendbe. Minél egyedibb az üzleti logika, annál jobb.
  4. Konvertálja az alkalmazás IO részeit, az adatbázis rétegeket, a sorokat és így tovább.
  5. Konvertálja a teszteket.

Ne feledje, hogy vannak automatizált eszközök, amelyek megkönnyítik ezt a folyamatot, például ts-migrate az Airbnb csapatától.

Más szempontból kezeli ezt a problémát, és az összes fájlt átalakítja TypeScript-be. Ez fokozatos fejlesztéseket is lehetővé tesz (amint azt a fenti lépésekben említettük), miközben a teljes kódbázis az első naptól TypeScript.

Hogyan lehet konvertálni egy JavaScript alkalmazást a TypeScript támogatására.

Telepítse a gépírót

futtatásával: npm install typescript.

Gépirat konfigurációs fájl

Adjon hozzá egy gépírási konfigurációs fájlt, amelyet a tsc --initCLI parancsával hozhat létre .

Íme egy példa arra, hogyan nézett ki a kezdeti konfigurációnk:

{ "compilerOptions": { "target": "esnext", "module": "commonjs", "allowJs": true, "checkJs": false, "outDir": "dist", "rootDir": ".", "strict": false, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ "declaration": true, /* Generates corresponding '.d.ts' file. */ "strictNullChecks": true, "resolveJsonModule": true, "sourceMap": true, "baseUrl": ".", "paths": { "*": [ "*", "src/*", "src/setup/*", "src/logic/*", "src/models/*", "config/*" ] }, }, "exclude": ["node_modules", "dist"], "include": [ "./src", "./test", "./*", "./config" ] }

Néhány dolog, amit észre kell venni:

  • A srcvagy testvagy configkönyvtár összes fájlját elolvastuk (a includezászló használatával).
  • A JavaScript fájlokat bemenetként fogadjuk el (a allowJsflag használatával).
  • Az összes kimeneti fájlt a build(z) használatával bocsátjuk ki outDirflag.

Hozza létre az első .TS fájlt a projektben

Azt javaslom, hogy kezdje el egy egyszerű TypeScript fájl hozzáadásával (vagy egy igazán egyszerű JS fájl TS-vé változtatásával), és telepítse. Tegye ezt az átállást egyenként.

Vigyázzon a package.json fájlra

Így package.jsonnéz ki előttünk és utánunk:

{ "scripts": { "start": "node ./application.js", "mocha": "mocha --recursive --reporter spec -r test/bootstrap.js", "test": "npm run mocha -- test/ -r test/integration/bootstrap.js", } }
{ "scripts": { "start": "node ./dist/application.js", "build-dist": "./node_modules/typescript/bin/tsc", "mocha": "mocha --recursive --reporter spec -r ./dist/test/bootstrap.js", "test": "npm run mocha -- ./dist/test/ -r ./dist/test/integration/bootstrap.js" } }

As you can see, most of the changes were about adding the prefix dist to most of our build commands. We also added a build-dist script that compiles our codebase and moves all files to a dedicated folder called dist.

Add source-map-support

One of the big issues when adding TypeScript to your project is that you are adding a layer of indirection between the code you write and the code that actually runs in production (since .ts is transpiled  to .js  in run time).

For example, imagine the following TypeScript program:

const errorMessage: string = "this is bad" throw new Error(a)

When we run it, it will throw the following stack-trace:

Error: this is bad at Object. (/Users/dorsev/work/git/example/hello.js:3:7)

This is problematic since our code-base contains only .ts files. And since most production code contains hundreds of lines, it will be really time-consuming translating these numbers and files properly.

Luckily for us, there is a solution for this called source-map-support!

This allows us to ensure that stack-traces will have proper .ts file names and line numbers like we are used to :)

This can be done by running npm install source-map-support and then adding the following line in the first lines of your application:

require('source-map-support').install();

The code now looks like this:

require('source-map-support').install(); const a:string = "this is bad" throw new Error(a)

And when we compile it we run tsc --sourcemap hello.ts. Now we get the following stack-trace which is awesome :)

Error: this is bad at Object. (/Users/dorsev/work/git/example/hello.ts:3:7)

In recent versions of nodejs, this is supported natively by using the --enable-source-maps flag.

How to take care of your build (Travis) & packaging

Let's just examine the before and after changes on our build configuration file.

This is how our .travis file looked before (simplified edition):

jobs: include: - &build-and-publish before_script: - npm install --no-optional --production - npm prune --production before_deploy: - XZ_OPT=-0 tar --exclude=.git --exclude=reports.xml --exclude=${ARTIFACTS_MAIN_DIR} --exclude=.travis.yml --exclude=test -cJf "${ARTIFACTS_PATH}/${REPO_NAME}".tar.xz * .??* - &test before_script: - npm install --no-optional script: - echo "Running tests" - npm run lint && npm test

And this is how it looked after:

jobs: include: - &build-and-publish before_script: - npm install --no-optional --production - npm run build-dist # Build dist folder - npm prune --production before_deploy: - cp -rf config/env-templates ./dist/config/ - cp -rf node_modules ./dist/ - cd dist - XZ_OPT=-0 tar --exclude=.git --exclude=reports.xml --exclude=${ARTIFACTS_MAIN_DIR} --exclude=.travis.yml --exclude=test -cJf "${REPO_NAME}.tar.xz" * - mv ${REPO_NAME}.tar.xz "../${ARTIFACTS_PATH}" - cd .. - &test before_script: - npm install --no-optional - npm run build-dist script: - echo "Running tests" - npm run lint && npm test

Notice most changes concern "packaging" to the tar.xz file and running the build-dist command before accessing the dist folder.

How can I take care of linting?

There are a couple of linting solutions available.

The first solution we used was tsfmt  –  but then we decided against it later on because it requires you to maintain two separate configurations for your project (one for TypeScript using tsfmt and a separate one for JavaScript using eslint). The project also looks deprecated.

We then found TSLint  which redirected us to the eslint plugin for TypeScript. We then configured it as follows:

This was our eslintrc.js:

module.exports = { rules: { indent: [2, 2, { SwitchCase: 1 }], 'no-multi-spaces': 2, 'no-trailing-spaces': 2, 'space-before-blocks': 2, }, overrides: [{ files: ['**/*.ts'], parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], extends: ['plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended'] }] }

Which we configured to run using a lint-fix command in our package.json which looks as follows:

{ "scripts": { "lint-fix": "node_modules/.bin/eslint . --fix" }, "pre-commit": ["lint-fix"] }

How to "sell" typescript to your development team

I believe one of the most critical aspects of introducing TypeScript to your organization is the "pitch" and how you present it to your development team.

Here is the presentation we presented internally which revolved around the following topics:

  1. Explain why we think TypeScript is awesome
  2. What is TypeScript
  3. Some basic code examples. The main point in this part is not to "teach" 100% TypeScript, since people will do that on their own. Instead, give people the feeling  that they can read and write TypeScript, and that the learning curve is not so hard.
  4. Advanced code examples, like Union types and Algebraic data-types which provide enormous values to a JS developer. This are a real treats, on top of typed-language and the compiler that will attract your developers to it.
  5. How to start using it. Encourage people to download the vs-code IDE and to add an annotation (//@ts-check) so they can start seeing the magic!  In our company, we prepared in advances some really cool mistakes that ts-check catches, and we did a live demo (2-3 minutes) to show how fast the TypeScript compiler can help them  using JS docs with type annotations or ts-check).
  6. Deep dive into some features. Explain ts.d files and @types packages which are some of the things you will encounter really early in your TypeScript codebases.
  7. Live PR's from your work. We showed the PR we created early on, and encouraged people to review it and try it out for themselves.
  8. Share some cool resources. There is a lot of content online, and it's hard to figure out good from bad. Do your teammates a solid and dig deeper and try to find quality content about the tools you use and need. Scroll down to the conclusion for my resources.
  9. Create a public pull request .  I recommend trying to get as much support as possible for its approval.

10.  Create a positive buzz in your organization about the change!

I highly recommend tweaking this list according to your team, standards, and time-constraints.

Conclusion

Typescript is super awesome! If you are writing production grade software and the business requirements and availability are high, I strongly encourage you to give typescript a try.

Just remember to take it one step at a time. New languages and frameworks are hard, so take the time to learn and to educate yourself and your team before pushing this process forward.

Create a short feedback loop and value proposition. It's hard to "sell" a new language to your team and management as it takes time and resources.

So design your migration process with short feedback loops, and try to define clear KPI's (fewer bugs in production, easier refactoring times, and so on) and make sure the value proposition for your use-case is constantly justified until it becomes the de-facto standard.  

Make learning resources readily available. I really enjoyed this talk about TypeScript first steps and this blog post about incremental migration to TypeScript.

Also, don't miss out on the deno project and the ts-node project. I'm super excited and looking forward to using them soon.