Full Stack Open Part9
Preparation
Type Definition for Third Party Libraries
In TypeScript, we want every variable to have a type defined in order to perform further static checks.
But in some cases, we would need third party libraries which are not written in TypeScript(therefore don’t contain types).
Under this circumstance, we could look for the community-maintained type packages, for example,
express
andcors
.1
2
3yarn add express
yarn add -D @types/express
yarn add -D cors @types/cors
Eslint
To configure a project, for example an Express.js backend, we will need these packages installed:
1
yarn add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
Then, create a
eslint.config.mjs
as the config file for eslint:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61import typescriptEslint from "@typescript-eslint/eslint-plugin";
import globals from "globals";
import tsParser from "@typescript-eslint/parser";
import path from "node:path";
import { fileURLToPath } from "node:url";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
const **filename = fileURLToPath(import.meta.url);
const **dirname = path.dirname(**filename);
const compat = new FlatCompat({
baseDirectory: **dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
...compat.extends(
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
),
{
plugins: {
"@typescript-eslint": typescriptEslint,
},
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
parser: tsParser,
ecmaVersion: 5,
sourceType: "commonjs",
parserOptions: {
project: "./tsconfig.json",
},
},
rules: {
"@typescript-eslint/semi": ["error"],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
},
],
"no-case-declarations": "off",
},
},
{
ignores: ["eslint.config.mjs", "node_modules/", "build/"],
},
];For more information about configuration of Eslint above version 9.0, refer to Configure ESLint.
tsconfig.json
To set up some compile(transpile) options for the current project, we would need a
tsconfig.json
under the root directory.We can use
tsc
to auto-generate one:Firstly, install the native compiler of TypeScript
tsc
by:1
yarn add -D typescript
Secondly, add related script in
package.json
:1
2
3
4
5
6
7
8{
...,
"scripts": {
"tsc": "tsc",
...
},
...
}Finally, run
yarn tsc --init
to generate thetsconfig.json
file automatically.
As the course required, these compiler options should be written to
tsconfig.json
:1
2
3
4
5
6
7
8
9
10
11
12
13{
"compilerOptions": {
"target": "ES6",
"outDir": "./build/",
"module": "commonjs",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true
}
}For the auto-generated config file, we could just search for the related options and uncomment them.
CORS Issue
Discussed before in part3.b
If we want the resources returned by the backend to be accessed by a different origin or domain, we should install
cors
package and ‘use’ it inexpress
:1
yarn add -D cors @type/cors
1
2
3
4
5import express from "express";
import cors = require("cors");
const app: Express = express();
app.use(cors()); // this line is requried
Parse JSON HTTP Request Body
To accept data transmitted from the frontend in the http request body, we need to ‘use’ the json module of
express
:1
2
3
4import express from "express";
const app: Express = express();
app.use(json()); // this line is requried
Node and JSON Modules
There’s a way to import JSON files as a module and assign ‘type’ to the content imported.
To do this, we will need to enable the
resolveJsonModule
option intsconfig.json
:1
"resolveJsonModule": true /* Enable importing .json files. */,
By then, we can import data from JSON file just as we import it from a ts/js file:
1
2
3import diaries from "../../data/entries";
import { DiaryEntry } from "../types";But be noted of a problem that may arise when using the tsconfig
resolveJsonModule
option:By default, node will try to resolve modules in order of extensions:
1
["js", "json", "node"]
By enabling
resolveJsonModule
, the list of possible node module extensions is extended to:1
["js", "json", "node", "ts", "tsx"]
Then, consider a flat folder structure containing files:
1
2├── myModule.json
└── myModule.tsIn TypeScript, with the resolveJsonModule option set to true, the file myModule.json becomes a valid node module. Now, imagine a scenario where we wish to take the file myModule.ts into use:
1
import myModule from "./myModule";
We notice that the .json file extension takes precedence over .ts(from the extended node module extensions). So, myModule.json will be imported and not myModule.ts.
To avoid time-eating bugs, it is recommended that within a flat directory, each file with a valid node module extension has a unique filename.
Path Aliases(Mappings)
We can setup path aliases in
tsconfig.json
file to avoid related pathes import or long import statement. For example:1
2
3
4
5
6
7
8"baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
"paths": {
"@/*": ["src/*"],
"@data/*": ["data/*"],
"@utils/*": ["src/utils/*"],
"@services/*": ["src/services/*"],
"@routers/*": ["src/routers/*"]
} /* Specify a set of entries that re-map imports to additional lookup locations. */,
tsc & ts-node Ignoring Path Aliases
ts-node
andts-node-dev
will ignore the path aliases declared intsconfig.json
.
Dev
My preferred workaround for
ts-node-dev
is to use thetsconfig-paths
package:install
tsconfig-paths
:1
yarn add -D tsconfig-paths
then modify the command in
package.json
:1
2
3
4
5"scripts": {
...,
"dev": "tsnd --respawn -r tsconfig-paths/register index.ts",
...
}
Build
When it comes to the build stage, one more package needs to be added:
@ef-carbon/tspm
. For example:install
tsconfig-paths
and@ef-carbon/tspm
: …then modify the command in
package.json
:1
2
3...,
"build": "tsc && ef-tspm",
...
See Stack Overflow, GitHub, and also the github page of the two related libraries:
yarn create
I want to run this
npm
command withyarn
:1
npm create vite@latest my-app-name -- --template react-ts
The identical commands for
yarn
are:1
2yarn global add create-vite
create-vite --template react-ts
To Be Continued…
- Title: Full Stack Open Part9
- Author: Last
- Created at : 2024-07-08 17:52:12
- Link: https://blog.imlast.top/2024/07/08/fullstackopen-p9/
- License: This work is licensed under CC BY-NC-SA 4.0.