目录

  1. 为什么要在 Node.js 中使用 TypeScript
  2. 环境与依赖安装

  3. 编译与运行方式对比

  4. tsconfig.json 详解

  5. 项目示例:从零搭建 Node+TS

  6. 调试 TypeScript in Node.js

  7. 常见问题与解决方案
  8. 总结与最佳实践

为什么要在 Node.js 中使用 TypeScript

  1. 静态类型检查

    • TypeScript 在编译阶段就能发现常见的类型错误,避免运行时抛出“undefined is not a function”之类的错误。
  2. 更好的 IDE 支持

    • 类型提示、自动补全、重构跳转(Go To Definition)等功能,让编写 Node.js 代码更高效。
  3. 渐进式 Adoption

    • 可以增量地把 JavaScript 文件改为 .ts,配合 allowJscheckJs 选项,就能逐步引入类型定义。
  4. 面向大型项目

    • 随着项目规模增长,模块划分和接口契约更复杂,TS 的类型系统有助于维护可读性和可维护性。

环境与依赖安装

2.1 全局与项目依赖

全局安装(可选)

  • 在命令行中安装 TypeScript 编译器和 ts-node:

    npm install -g typescript ts-node
    • tsc:TypeScript 编译器
    • ts-node:可以直接在 Node.js 环境中运行 .ts 文件,无需手动编译

项目本地安装(推荐)

在项目根目录执行:

npm init -y
npm install --save-dev typescript ts-node nodemon @types/node
  • typescript:TS 编译器
  • ts-node:启动时动态编译并执行 .ts
  • nodemon:文件变化时自动重新启动
  • @types/node:Node.js 内置模块的类型定义

查看依赖:

npm list --depth=0

2.2 初始化 tsconfig.json

在项目根目录运行:

npx tsc --init

会生成一个默认的 tsconfig.json。初版内容类似:

{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

接下来我们会在第 4 节进行详细解读,并根据实际需求进行调整。


编译与运行方式对比

Node.js 运行 TypeScript 主要有两种思路:实时编译执行预先编译再运行。下面逐一说明优劣和示例。

3.1 直接使用 ts-node 运行

  • 优点:启动简单、无需手动编译,适合开发阶段快速迭代。
  • 缺点:启动速度稍慢、对生产环境不推荐(性能损耗),不产出纯 JavaScript 代码。

示例

假设有 src/index.ts

// src/index.ts
import http from 'http';

const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  res.end('Hello TypeScript on Node.js!');
});

server.listen(PORT, () => {
  console.log(`Server listening on http://localhost:${PORT}`);
});

package.json 中添加脚本:

{
  "scripts": {
    "dev": "ts-node src/index.ts"
  }
}

然后启动:

npm run dev

控制台输出:

Server listening on http://localhost:3000

3.2 预先编译再用 node 运行

  • 优点:可生成干净的 JS 输出,适合生产环境部署;更快启动。
  • 缺点:需要维护编译与运行之间的命令链,稍微麻烦些。

步骤

  1. tsconfig.json 中指定输出目录
    例如:

    {
      "compilerOptions": {
        "outDir": "dist",
        "rootDir": "src",
        "target": "ES2018",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true
      }
    }
  2. 编译命令
    package.json 增加:

    {
      "scripts": {
        "build": "tsc",
        "start": "npm run build && node dist/index.js"
      }
    }
  3. 运行

    npm run start
    • tsc 会将 src/*.ts 编译到 dist/*.js
    • Node.js 执行编译后的 dist/index.js

3.3 ESModule 模式下的 TypeScript

如果想使用 ESModule (import/export) 而非 CommonJS (require),需要做以下调整:

  1. package.json 中指定:

    {
      "type": "module"
    }
  2. tsconfig.json 中设置

    {
      "compilerOptions": {
        "module": "ES2020",
        "target": "ES2020",
        "moduleResolution": "node",
        "outDir": "dist",
        "rootDir": "src",
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
      }
    }
  3. 文件后缀

    • 在代码里引用时,要加上文件后缀 .js(编译后是 .js)。
    • 示例:import { foo } from './utils.js';

示例 src/index.ts

import http from 'http';
import { greet } from './utils.js';

const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  res.end(greet('TypeScript'));
});

server.listen(PORT, () => {
  console.log(`Server listening on http://localhost:${PORT}`);
});

示例 src/utils.ts

export function greet(name: string): string {
  return `Hello, ${name}!`;
}

编译与运行

npm run build
node --experimental-specifier-resolution=node dist/index.js
在较新版本的 Node.js(≥16)中,通常不需要 --experimental-specifier-resolution=node,只要文件后缀正确即可。

3.4 Hot Reload:nodemonts-node-dev

开发阶段通常希望在源代码修改后自动重启服务,可选择两种常用工具:

  1. nodemon + ts-node

    • nodemon.json 配置:

      {
        "watch": ["src"],
        "ext": "ts,js,json",
        "ignore": ["dist"],
        "exec": "ts-node src/index.ts"
      }
    • 启动:npx nodemon
  2. ts-node-dev

    • 安装:npm install --save-dev ts-node-dev
    • 脚本:

      {
        "scripts": {
          "dev": "ts-node-dev --respawn --transpile-only src/index.ts"
        }
      }
    • 启动:npm run dev
    • 相比 nodemonts-node-dev 带有更快的增量重编译与内存缓存。

tsconfig.json 详解

tsconfig.json 是 TypeScript 编译器的核心配置文件,下面对常用选项进行解释,并给出完整示例。

4.1 常用编译选项示例

{
  "compilerOptions": {
    /* 指定 ECMAScript 目标版本 */
    "target": "ES2019",             // 可选 ES3, ES5, ES6/ES2015, ES2017, ES2019, ES2020...

    /* 指定模块系统 */
    "module": "commonjs",           // 可选 commonjs, es2015, es2020, esnext

    /* 输出目录与输入目录 */
    "rootDir": "src",               // 源代码根目录
    "outDir": "dist",               // 编译输出目录

    /* 开启严格模式 */
    "strict": true,                 // 严格类型检查,包含下面所有选项

    /* 各类严格检查 */
    "noImplicitAny": true,          // 禁止隐式 any
    "strictNullChecks": true,       // 严格的 null 检查
    "strictFunctionTypes": true,    // 函数参数双向协变检查
    "strictBindCallApply": true,    // 严格的 bind/call/apply 检查
    "strictPropertyInitialization": true, // 类属性初始化检查
    "noImplicitThis": true,         // 检查 this 的隐式 any
    "alwaysStrict": true,           // 禁用严格模式下的保留字(js 严格模式)

    /* 兼容性与交互 */
    "esModuleInterop": true,        // 允许默认导入非 ES 模块
    "allowSyntheticDefaultImports": true, // 允许从没有默认导出的模块中默认导入
    "moduleResolution": "node",      // 模块解析策略(node 或 classic)
    "allowJs": false,               // 若为 true,会编译 .js 文件
    "checkJs": false,               // 若为 true,检查 .js 文件中的类型

    /* SourceMap 支持,用于调试 */
    "sourceMap": true,              // 生成 .js.map 文件
    "inlineSources": true,          // 将源代码嵌入到 SourceMap

    /* 路径映射与别名 */
    "baseUrl": ".",                 // 相对路径基准
    "paths": {                      // 别名配置
      "@utils/*": ["src/utils/*"],
      "@models/*": ["src/models/*"]
    },

    /* 库文件 */
    "lib": ["ES2019", "DOM"],       // 在 TypeScript 中引入的全局类型声明文件

    /* 构建优化 */
    "incremental": true,            // 开启增量编译
    "skipLibCheck": true,           // 跳过声明文件的类型检查,加速编译
    "forceConsistentCasingInFileNames": true // 文件名大小写一致
  },
  "include": ["src"],               // 包含的文件或目录
  "exclude": ["node_modules", "dist"] // 排除的目录
}

解析

  • target:设为 ES2019 或更高可以使用现代 JS 特性(如 Object.fromEntries)。
  • module:在 CommonJS 环境下请使用 commonjs,若要输出 ES Module,改为 es2020
  • esModuleInterop:与 Babel/webpack 联动更方便,允许 import fs from 'fs' 而不是 import * as fs from 'fs'
  • sourceMap + inlineSources:用于调试,使得在 VSCode 中能准确定位到 .ts 源文件。
  • paths:结合 baseUrl 可自定义模块别名,减少相对路径导入的冗长。

4.2 Paths 与 Module Resolution

当你在代码里写:

import { helper } from '@utils/helper';

需要在 tsconfig.json 中配置:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@utils/*": ["src/utils/*"]
    }
  }
}

这样,TypeScript 编译器在解析 @utils/helper 时会映射到 src/utils/helper.ts。运行时需要配合 module-alias 或在编译后通过构建工具(Webpack、tsc-alias)替换路径。


4.3 示意图:模块解析流程

                    import x from '@models/user'
                                │
                                ▼
                   ┌─────────────────────────┐
                   │  TypeScript 编译器解析  │
                   └─────────────────────────┘
                                │ (paths 配置)
                                ▼
             @models/user  ───>  src/models/user.ts
                                │
                                ▼
                   ┌─────────────────────────┐
                   │  输出 JavaScript 文件    │
                   │ dist/models/user.js     │
                   └─────────────────────────┘
                                │
                                ▼
                   ┌─────────────────────────┐
                   │  Node.js 加载 dist/...   │
                   └─────────────────────────┘
  • “@models/user” → 映射至 “src/models/user.ts”
  • 编译后输出至 “dist/models/user.js”,Node.js 直接加载即可

项目示例:从零搭建 Node+TS

下面演示一个完整的示例项目,从目录结构到关键代码,一步步搭建一个简单的用户认证 API。

5.1 目录结构

my-typescript-node-app/
├── src/
│   ├── config/
│   │   └── default.ts
│   ├── controllers/
│   │   └── auth.controller.ts
│   ├── services/
│   │   └── auth.service.ts
│   ├── models/
│   │   └── user.model.ts
│   ├── utils/
│   │   └── jwt.util.ts
│   ├── middleware/
│   │   └── auth.middleware.ts
│   ├── index.ts
│   └── app.ts
├── tsconfig.json
├── package.json
└── .env

5.2 关键文件详解

5.2.1 tsconfig.json

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "rootDir": "src",
    "outDir": "dist",
    "strict": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@models/*": ["src/models/*"],
      "@utils/*": ["src/utils/*"]
    },
    "skipLibCheck": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

5.2.2 .env

PORT=4000
JWT_SECRET=MySuperSecretKey

5.2.3 src/config/default.ts

// src/config/default.ts
import dotenv from 'dotenv';
dotenv.config();

export default {
  port: process.env.PORT || 3000,
  jwtSecret: process.env.JWT_SECRET || 'default_secret'
};

5.2.4 src/models/user.model.ts

// src/models/user.model.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column({ unique: true })
  username!: string;

  @Column()
  password!: string; // 已经 bcrypt hash 过

  @Column()
  email!: string;
}

5.2.5 src/utils/jwt.util.ts

// src/utils/jwt.util.ts
import jwt from 'jsonwebtoken';
import config from '../config/default';

export function signToken(payload: object): string {
  return jwt.sign(payload, config.jwtSecret, { expiresIn: '1h' });
}

export function verifyToken(token: string): any {
  return jwt.verify(token, config.jwtSecret);
}

5.2.6 src/services/auth.service.ts

// src/services/auth.service.ts
import { getRepository } from 'typeorm';
import bcrypt from 'bcrypt';
import { User } from '@models/user.model';
import { signToken } from '@utils/jwt.util';

export class AuthService {
  static async register(username: string, password: string, email: string) {
    const repo = getRepository(User);
    const existing = await repo.findOne({ where: { username } });
    if (existing) {
      throw new Error('用户名已存在');
    }
    const hash = await bcrypt.hash(password, 10);
    const user = repo.create({ username, password: hash, email });
    const saved = await repo.save(user);
    return saved;
  }

  static async login(username: string, password: string) {
    const repo = getRepository(User);
    const user = await repo.findOne({ where: { username } });
    if (!user) throw new Error('用户不存在');
    const match = await bcrypt.compare(password, user.password);
    if (!match) throw new Error('密码错误');
    const token = signToken({ id: user.id, username: user.username });
    return { token, user };
  }
}

5.2.7 src/controllers/auth.controller.ts

// src/controllers/auth.controller.ts
import { Request, Response } from 'express';
import { AuthService } from '../services/auth.service';

export class AuthController {
  static async register(req: Request, res: Response) {
    try {
      const { username, password, email } = req.body;
      const user = await AuthService.register(username, password, email);
      res.status(201).json({ success: true, data: user });
    } catch (err: any) {
      res.status(400).json({ success: false, message: err.message });
    }
  }

  static async login(req: Request, res: Response) {
    try {
      const { username, password } = req.body;
      const result = await AuthService.login(username, password);
      res.json({ success: true, data: result });
    } catch (err: any) {
      res.status(400).json({ success: false, message: err.message });
    }
  }
}

5.2.8 src/middleware/auth.middleware.ts

// src/middleware/auth.middleware.ts
import { Request, Response, NextFunction } from 'express';
import { verifyToken } from '@utils/jwt.util';

export function authMiddleware(req: Request, res: Response, next: NextFunction) {
  const header = req.headers.authorization;
  if (!header) {
    return res.status(401).json({ success: false, message: '缺少令牌' });
  }
  const token = header.split(' ')[1];
  try {
    const payload = verifyToken(token);
    (req as any).user = payload;
    next();
  } catch {
    res.status(401).json({ success: false, message: '无效或过期的令牌' });
  }
}

5.2.9 src/app.ts

// src/app.ts
import express from 'express';
import 'reflect-metadata';
import { createConnection } from 'typeorm';
import config from './config/default';
import { User } from '@models/user.model';
import { AuthController } from './controllers/auth.controller';
import { authMiddleware } from './middleware/auth.middleware';

export async function createApp() {
  // 1. 初始化数据库连接
  await createConnection({
    type: 'sqlite',
    database: 'database.sqlite',
    entities: [User],
    synchronize: true,
    logging: false
  });

  // 2. 创建 Express 实例
  const app = express();
  app.use(express.json());

  // 3. 公共路由
  app.post('/register', AuthController.register);
  app.post('/login', AuthController.login);

  // 4. 受保护路由
  app.get('/profile', authMiddleware, (req, res) => {
    // (req as any).user 包含 token 中的 payload
    res.json({ success: true, data: (req as any).user });
  });

  return app;
}

5.2.10 src/index.ts

// src/index.ts
import config from './config/default';
import { createApp } from './app';

async function bootstrap() {
  const app = await createApp();
  app.listen(config.port, () => {
    console.log(`Server running at http://localhost:${config.port}`);
  });
}

bootstrap().catch((err) => {
  console.error('启动失败:', err);
});

5.3 示例业务代码运行方式

  1. 安装依赖

    npm install express typeorm sqlite3 bcrypt jsonwebtoken @types/express @types/jsonwebtoken
  2. 开发模式

    npx ts-node src/index.ts
  3. 编译后运行

    npm run build   # tsc
    node dist/index.js

测试流程:

  • 注册

    curl -X POST http://localhost:4000/register \
      -H "Content-Type: application/json" \
      -d '{"username":"alice","password":"pass123","email":"alice@example.com"}'
  • 登录

    curl -X POST http://localhost:4000/login \
      -H "Content-Type: application/json" \
      -d '{"username":"alice","password":"pass123"}'

    返回:

    {
      "success": true,
      "data": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "user": { "id":1,"username":"alice", ... }
      }
    }
  • 访问受保护接口

    curl http://localhost:4000/profile \
      -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

调试 TypeScript in Node.js

6.1 生成 Source Map

已在 tsconfig.json 中开启:

"sourceMap": true,
"inlineSources": true

编译后会在 dist/ 目录看到 .js 与对应的 .js.map。这样在调试器里就能映射到 .ts 文件。

6.2 在 VSCode 中断点调试

  1. .vscode/launch.json 添加:

    {
      "version": "0.2.0",
      "configurations": [
        {
          "type": "node",
          "request": "launch",
          "name": "Debug TS",
          "runtimeArgs": ["-r", "ts-node/register"],
          "args": ["${workspaceFolder}/src/index.ts"],
          "cwd": "${workspaceFolder}",
          "protocol": "inspector",
          "env": {
            "NODE_ENV": "development",
            "PORT": "4000"
          },
          "sourceMaps": true,
          "console": "integratedTerminal"
        }
      ]
    }
  2. 设置断点

    • src/ 目录下打开任何 .ts 文件,点击行号左侧即可设置断点。
    • 在 Debug 面板选择 “Debug TS” 并启动,代码会在 TS 源文件层面断点。

常见问题与解决方案

  1. Cannot use import statement outside a module

    • 检查 package.json 是否包含 "type": "module" 或者将 tsconfig.jsonmodule 改为 commonjs
  2. 模块解析失败 (Cannot find module '@models/user.model')

    • 确认 tsconfig.jsonpathsbaseUrl 配置正确,并在编译后使用 tsconfig-pathstsc-alias
  3. Property 'foo' does not exist on type 'Request'

    • 需要扩展类型定义,例如:

      // src/types/express.d.ts
      import { Request } from 'express';
      
      declare module 'express-serve-static-core' {
        interface Request {
          user?: any;
        }
      }

      并在 tsconfig.jsoninclude 加入 src/types/**/*.ts

  4. ts-node 性能慢

    • 可以加上 --transpile-only 跳过类型检查:

      ts-node --transpile-only src/index.ts
    • 或使用 ts-node-dev

      npx ts-node-dev --respawn --transpile-only src/index.ts
  5. 生产环境如何部署 TS 项目

    • 一般先运行 npm run buildtsc),再启动编译后的 dist/index.js;避免在生产环境使用 ts-node,因为它没有预编译,性能较差,也不利于故障排查。

总结与最佳实践

  1. 增量迁移

    • 如果已有纯 JS 项目,可在 tsconfig.json 中开启 allowJscheckJs,逐步将 .js 改为 .ts
  2. 严格模式

    • 开启 strict,配置更自由和安全,有助于在编译时捕获更多潜在错误。
  3. 模块别名

    • 配合 paths 与对应的运行时替换工具(tsconfig-pathsmodule-alias),避免相对路径过于冗长。
  4. 分层结构

    • 将业务逻辑分为 controllersservicesmodels,中间件与工具代码放在独立目录,提高可维护性。
  5. 调试与日志

    • 开启 sourceMap,在开发环境使用 VSCode 或 Chrome DevTools 调试。
    • 引入 winstonpino 等日志库,并根据 NODE\_ENV 切换不同级别输出。
  6. 编译产物管理

    • .gitignore 中忽略 dist/node_modules/
    • 定期清理 dist/,执行 tsc --build --clean

通过以上配置与示例,你可以轻松在 Node.js 中运行 TypeScript 代码,从开发到生产部署都能保障类型安全与高效。

2024-09-09



import { Connection, createConnection } from 'typeorm';
import { User } from './entity/User';
 
async function connectDatabase() {
  const connection: Connection = await createConnection({
    type: 'sqlite',
    database: 'path/to/database.sqlite',
    entities: [User],
    synchronize: true,
  });
 
  // 使用 connection 对象操作数据库
  // 例如:查询所有用户
  const users = await connection.getRepository(User).find();
  console.log(users);
}
 
connectDatabase().catch(error => console.error(error));

这段代码演示了如何在Electron应用中使用Vite和Vue 3结合TypeScript,并利用TypeORM这一ORM工具来操作SQLite数据库。首先导入了TypeORM的Connection和创建数据库连接的createConnection函数,以及定义好的实体User。然后定义了一个异步函数connectDatabase来创建数据库连接,并在连接成功后进行操作,比如查询所有用户数据。最后,调用connectDatabase函数并捕获可能出现的错误。

2024-09-04



import axios from 'axios';
 
interface Article {
  title: string;
  content: string;
}
 
// 使用axios获取网页上的文章数据
async function fetchArticles(): Promise<Article[]> {
  try {
    const response = await axios.get('https://your-api-endpoint.com/articles');
    return response.data;
  } catch (error) {
    console.error('Error fetching articles:', error);
    return [];
  }
}
 
// 使用示例
fetchArticles().then(articles => {
  console.log(articles);
});

这段代码展示了如何在TypeScript中使用axios库来发送HTTP GET请求,并处理可能发生的错误。它定义了一个Article接口来描述文章数据的结构,然后定义了一个异步函数fetchArticles来获取文章数据。在获取数据的过程中,它使用了try-catch来处理潜在的异常,并在成功获取数据时返回这些数据,在发生错误时则记录错误并返回一个空数组。最后,它提供了一个使用示例来调用fetchArticles函数并打印结果。

2024-09-04

以下是一个简化的React、TypeScript、NodeJS和MongoDB搭建的Todo App前端自我介绍部分的代码示例:




import React, { useState } from 'react';
import { Button, Form } from 'react-bootstrap';
import { useHistory } from 'react-router-dom';
import { useAppDispatch } from '../app/hooks';
import { addUser } from '../features/user/userSlice';
 
export const Intro: React.FC = () => {
  const [name, setName] = useState('');
  const history = useHistory();
  const dispatch = useAppDispatch();
 
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (name) {
      dispatch(addUser({ name }));
      history.push('/tasks');
    }
  };
 
  return (
    <div className="intro-container">
      <h1>Welcome to Task Manager</h1>
      <Form onSubmit={handleSubmit}>
        <Form.Group>
          <Form.Label>What's your name?</Form.Label>
          <Form.Control
            type="text"
            placeholder="Enter your name"
            onChange={(e) => setName(e.target.value)}
            value={name}
            required
          />
        </Form.Group>
        <Button variant="primary" type="submit">
          Submit
        </Button>
      </Form>
    </div>
  );
};

这段代码使用React Hooks和Bootstrap进行了简洁的重构,它展示了如何使用useState管理表单输入状态,使用useHistory进行路由跳转,以及如何通过Redux Toolkit中的useAppDispatchaddUser函数更新用户信息。这个示例代码简洁明了,并且遵循了现代React和TypeScript开发的最佳实践。

2024-09-04



// 引入需要的模块
import { Entity, PrimaryKey, Property } from 'turso-sqlite';
 
// 定义一个用户实体
@Entity()
export class User {
    // 定义一个主键
    @PrimaryKey()
    id!: number;
 
    // 定义一个属性,这里是用户名
    @Property()
    username!: string;
 
    // 定义一个属性,这里是用户的密码哈希
    @Property()
    passwordHash!: string;
}
 
// 创建数据库实例并打开连接
const db = new Database();
await db.open('path/to/database.db');
 
// 创建一个新用户
const newUser = new User();
newUser.username = 'johndoe';
newUser.passwordHash = 'some-hashed-password';
 
// 将用户实体插入数据库
await db.table(User).add(newUser);
 
// 查询用户
const users = await db.table(User).getAll();
 
// 关闭数据库连接
await db.close();

这个简单的例子展示了如何使用turso-sqlite库来定义一个用户实体,并对其进行增删改查操作。在实际应用中,你需要处理更复杂的业务逻辑,并确保正确地处理安全性相关的问题,例如密码的哈希处理。

2024-08-27

在TypeScript中,类型断言提供了一种明确告诉编译器变量的类型的方法。你可以使用 as 关键字或者 <类型> 的形式来进行类型断言。

例如,假设你有一个 value 变量,它可能是 string 类型也可能是 number 类型。你可以在知道它是 string 类型的时候进行类型断言:




let value: string | number;
 
// 使用 as 关键字断言
let strValue1 = (value as string).toUpperCase();
 
// 使用 <> 形式断言
let strValue2 = (<string>value).toUpperCase();

请注意,类型断言并不会改变运行时的行为,它只是提供给TypeScript编译器一个类型信息。如果你断言了一个变量是一个不正确的类型,在运行时可能会抛出错误。因此,使用类型断言时需要确保断言的类型是正确的。

2024-08-27



// 定义一个简单的接口
interface Point {
  x: number;
  y: number;
}
 
// 使用接口来定义一个函数,该函数接收一个符合Point接口的对象
function printCoord(point: Point) {
  console.log('x: ' + point.x + ', y: ' + point.y);
}
 
// 创建一个符合Point接口的对象
const point: Point = { x: 100, y: 200 };
 
// 调用函数并传入该对象
printCoord(point);

这段代码首先定义了一个Point接口,该接口有xy两个属性,分别代表坐标系中的x坐标和y坐标。然后定义了一个printCoord函数,该函数接受一个类型为Point的对象作为参数,并打印出该对象的坐标。最后,创建了一个符合Point接口的对象,并调用printCoord函数来输出这个点的坐标。这个例子展示了接口的基本使用方法,并且有助于理解接口在TypeScript中的作用。

2024-08-27



// 假设有一个函数,它接受一个联合类型的参数,并根据类型不同执行不同的操作
function processInput(input: string | number): string {
    // 使用类型断言来确保在处理input时,我们可以调用toString()
    const stringInput = input.toString();
    // 根据不同的类型,执行不同的逻辑
    if (typeof input === 'string') {
        return stringInput.toUpperCase();
    } else {
        return stringInput.toString();
    }
}
 
// 使用类型断言来确保我们可以调用特定于字符串的方法
const myStringValue: string | number = "Hello, TypeScript!";
const processedValue = processInput(myStringValue);
 
console.log(processedValue); // 输出: "HELLO, TYPESCRIPT!"

这个例子展示了如何在TypeScript中使用类型断言来确保代码可以编译通过并正确地处理不同类型的输入。这是TypeScript中类型系统的一个关键特性,它允许开发者在编写类型安全的代码时更加灵活。

2024-08-27

在Vue项目中使用TypeScript需要以下步骤:

  1. 确保你的项目已经支持TypeScript。如果还没有安装typescript,可以通过npm或yarn安装:

    
    
    
    npm install -g typescript
  2. 在项目中安装TypeScript支持:

    
    
    
    npm install --save-dev typescript
  3. 创建一个tsconfig.json文件,该文件定义了TypeScript编译选项:

    
    
    
    npx tsc --init
  4. 安装vue类型定义文件和vue-class-component装饰器支持:

    
    
    
    npm install --save-dev @vue/cli-plugin-typescript @vue/cli-plugin-babel
    npm install --save-dev vue-class-component
  5. 修改vue项目中的<script>标签,使其可以支持TypeScript:

    
    
    
    <script lang="ts">
    import Vue from 'vue';
    export default Vue.extend({
      // Options
    });
    </script>
  6. <script>标签中编写TypeScript代码。

以下是一个简单的Vue组件示例,使用TypeScript编写:




<template>
  <div>{{ message }}</div>
</template>
 
<script lang="ts">
import Vue from 'vue';
 
export default Vue.extend({
  data() {
    return {
      message: 'Hello, Vue with TypeScript!'
    };
  }
});
</script>
 
<style scoped>
div {
  color: blue;
}
</style>

这个组件在<template>中显示一条消息,并在<script>标签中使用TypeScript编写。当你在Vue CLI创建的项目中这样配置后,就可以使用TypeScript来编写Vue应用了。