使用 TS 写一个简单的命令行程序

973 阅读1分钟

环境:Mac OS

前置条件:已安装 node 和 npm

开发工具: VS Code

安装与调试

全局安装 ts 和 ts-node

npm install typescript@2.9.2 -g
npm install ts-node@7.0.0 -g

记录下安装完 ts-node 之后的可执行文件路径。

image.png

新建一个目录 tsdemo,并在其中新建一个 1.ts 文件,在文件中写 console.log('Hello, TS!')然后保存。

Windows 用户注意,这里需要单独运行一些命令(Linux 用户和 macOS 用户不用执行)

npm init -y
npm i -D ts-node typescript

在 tsdemo 下创建 .vscode 目录,在其中创建 launch.json ,内容如下:

 {
     "configurations": [
         {
         "name": "ts-node",
         "type": "node",
         "request": "launch",
         "program": "注意这里,要写成ts-node对应的可执行文件;Windows 用户注意,应该写成 ${workspaceRoot}/node_modules/ts-node/dist/bin.js",
         "args": ["${relativeFile}"],
         "cwd": "${workspaceRoot}",
         "protocol": "inspector"
         }
     ]
 }

使用 VS Code 打开 tsdemo 下的 1.ts,找到调试,

image.png

看到结果后说明调试正常(注意选中的文件确定是 1.ts)。

image.png

命令行程序

在 tsdemo 下新建一个 add.ts 文件

#!/usr/bin/env ts-node
console.log('hello world')

#!/usr/bin/env ts-node 这一行注释代码有历史渊源,叫 shebang

然后给 add.ts 文件添加执行权限(Windows 用户不需要做这个,直接在 Git Bash 输入 ./1.ts 即可运行):

chmod +x ./1.ts

执行 ./1.ts ,输出 'hello world' 之后说明正常。

在 add.ts 中继续写代码:

#!/usr/bin/env ts-node
console.log('hello world')
console.log(process.argv)

此时再运行会报错:

/usr/local/lib/node_modules/ts-node/src/index.ts:261
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
2.ts(2,13): error TS2304: Cannot find name 'process'.

    at createTSError (/usr/local/lib/node_modules/ts-node/src/index.ts:261:12)
    at getOutput (/usr/local/lib/node_modules/ts-node/src/index.ts:367:40)
    at Object.compile (/usr/local/lib/node_modules/ts-node/src/index.ts:557:11)
    at Module.m._compile (/usr/local/lib/node_modules/ts-node/src/index.ts:439:43)
    at Module._extensions..js (module.js:663:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/usr/local/lib/node_modules/ts-node/src/index.ts:442:12)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)

process 是 Node.js 的全局变量,不可能找不到。其实原因是没有相关的类型声明。

这就是 TS 的厉害之处:如果你不告诉我 process 是什么,我就不允许你用 process。

那么如何告诉 TS process 是什么呢?

方法如下:

# 初始化项目的 package.json
> npm init -y
# 安装 node 相关的类型定义
> npm install @types/node
# 再次运行 ./add.ts
> ./add.ts
[ 'node', '/Users/frank/TypeScript/tsdemo/2.ts' ]

就可以了。

现在终于轮到写正常的代码了。

#!/usr/bin/env ts-node
function add(a: number, b: number): number {
  return a + b
}

const a = parseInt(process.argv[2])
const b = parseInt(process.argv[3])

if (Number.isNaN(a) || Number.isNaN(b)) {
  console.log('参数错误')
  process.exit(1)
}

console.log(add(a, b))
// 0一般代表程序正常执行结束
// 非0代表程序出错
// 正所谓幸福的家庭都是相似的,不幸的家庭却各有各的不幸
process.exit(0)

噢,还不行,执行后发现又报错了,

/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:261
    return new TSError(diagnosticText, diagnosticCodes)
           ^
TSError: ⨯ Unable to compile TypeScript:
1.ts(9,12): error TS2339: Property 'isNaN' does not exist on type 'NumberConstructor'.
1.ts(9,31): error TS2339: Property 'isNaN' does not exist on type 'NumberConstructor'.

    at createTSError (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:261:12)
    at getOutput (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:367:40)
    at Object.compile (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:557:11)
    at Module.m._compile (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:439:43)
    at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Object.require.extensions.<computed> [as .ts] (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/index.ts:442:12)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
    at Object.<anonymous> (/Users/lijingwei/.nvm/versions/node/v14.16.1/lib/node_modules/ts-node/src/bin.ts:147:12)

原因是代码里使用了 Number.isNaN 这个新语法,ts 虽然默认支持,但是必须配置之后才可使用。

配置的方法是在 tsdemo 目录下新建一个 tsconfig.json 文件:

{
  "compilerOptions": {
    "lib": ["ES2015"]
  }
}

此时再执行 ./add.ts 1 2 即可正常执行。

TS 第二天

写一个 tree.ts 。

#!/usr/bin/env ts-node

function createPrefix(n: number): string {
  return '----'.repeat(n)
}

class Person {
  // 默认值
  public children: Person[] = []
  constructor(public name: string) { }
  // 函数返回值为空
  addChild(child: Person): void {
    this.children.push(child)
  }
  // 接收可选参数
  introduceFamily(n?: number): void {
    n = n || 1
    console.log(`${createPrefix(n - 1)}${this.name}`)
    this.children.forEach(child => {
      child.introduceFamily(n + 1)
    })
  }
}

let grandPa = new Person('张麻子')
let child1 = new Person('张老大')
let child2 = new Person('张老二')
let person11 = new Person('张老大一')
let person12 = new Person('张老大二')
let person21 = new Person('张老二一')
let person22 = new Person('张老二二')


grandPa.addChild(child1)
grandPa.addChild(child2)

child1.addChild(person11)
child1.addChild(person12)

child2.addChild(person21)
child2.addChild(person22)

grandPa.introduceFamily()