TypeScript 基础语法

TypeScript 学习笔记


TypeScript 向 JavaScript 添加了额外的语法(添加了类型),与编辑器更紧密的集成,能在编辑器中尽早发现错误。

TypeScript 代码转换为 JavaScript,它在 JavaScript 运行的任何地方运行:在浏览器中、在 Node.js 或 Deno 上以及在你的应用程序中。

TypeScript 理解 JavaScript 并使用类型推断为你提供出色的工具,而无需额外的代码。

一、环境搭建

  1. 安装Node.js

在node中文网下载,安装长期支持版

https://nodejs.cn/
  1. 安装TypeScript(npm安装)
npm i -g typescript

查看typescript的版本

# 正常会显示版本,如:Version 5.2.2
tsc -v

如果出现下面错误

tsc : 无法加载文件 D:\opt\node\node-v18.16.0\tsc.ps1,因为在此系统上禁止运行脚本。

因为 PowerShell默认的执行策略是:Restricted,需要修改为:RemoteSigned

解决办法:

以管理员身份运行 PowerShell,在命令行输入

set-ExecutionPolicy RemoteSigned

在确认地方输入 y 或者 a

再查看设置结果

# 查看设置结果是否为:RemoteSigned
get-ExecutionPolicy

二、TypeScript基本语法

2.1 数据类型

数据类型

类型例子说明
numbera: number = 1数字
stringb: string = ‘wk’字符串
booleanc: boolean = true布尔
字面量let sex:‘male’ | ‘female’限制变量的值就是该字面量的值,类似定义常量
any任意类型
unknow类型安全的any,不能直接赋值给其它变量。
void空值(undefined)没有值
never没有值不能是任何值
object{ name: ‘wk’ }对象
array[1, 2, 3]数组
tuple[4,5]元组
enumenum(A, B)枚举
  1. 基本类型
  • string

  • number

  • boolean

  1. 数组

方式一

  • number[]

  • string[]

方式二:

  • Array

  • Array

示例

let a: string[]

let a: Array

  1. any

对变量的值不进行类型检查,类型可以使用any

let obj: any = {x: 0};
  1. union 联合类型,可以是多个类型中的一个

let u: string | number | boolean = ‘rose’

u = 18

  1. object

1)对象必须有name属性

let user: {name: string}

2)对象必须有name属性,age属性可选

let user: {name: string, age?: number}

3)对象必须有name属性,其它属性可用(属性值类型为any)

let user: {name: string, [prop: string]: any}

4)函数func有两个参数,参数类型为string,返回值类型为number

let func: (a: string, b: string) => number;

  1. 元组

元组是固定长度的数组。

定义元组h, 里面有2个类型为string的值。

let h: [string, string]

  1. 枚举
enum Gender {
    Male = 1,
    Female = 0
}

let user = {
    gender: Gender.Male
}
  1. 类型别名

myType是string的别名

type myType = string;
let a: myType
// 定义类型 myType是1 | 2 | 3 | 4 | 5的别名
type myType = 1 | 2 | 3 | 4 | 5
let a: myType
a = 1

2.2 运算符号

  1. & 与
// 变量j既有属性name, 又有属性age
let j: {name: string} & {age: number}  
j = {name: 'wk', age: 40}
  1. | 或

函数

function 函数名(param1: 参数类型, param2: 参数类型): 返回值类型 {

}

类型断言

let a: string = b as string

let a: string = b

变量作用域

变量作用域指定了变量定义的位置。

程序中变量的可用性由变量作用域决定。

TypeScript 有以下几种作用域:

1)全局作用域 − 全局变量定义在程序结构的外部,它可以在你代码的任何位置使用。

2)类作用域 − 这个变量也可以称为 字段。类变量声明在一个类里头,但在类的方法外面。 该变量可以通过类的对象来访问。类变量也可以是静态的,静态的变量可以通过类名直接访问。

3)局部作用域 − 局部变量,局部变量只能在声明它的一个代码块(如:方法)中使用。

以下实例说明了三种作用域的使用:

var global_num = 12 // 全局变量
class Numbers { 
  num_val = 13; // 实例变量
  static sval = 10; // 静态变量

  storeNum():void { 
    var local_num = 14; // 局部变量
  } 
} 
console.log("全局变量为: " + global_num)  
console.log(Numbers.sval) // 静态变量
var obj = new Numbers(); 
console.log("实例变量: " + obj.num_val)

2.3 条件语句

2.3.1 循环语句

  1. for 循环
  • 普通for循环
for (let i = 0; i < 10; i++) {
  console.log(i)
}
  • for in迭代
let cites = ['西安', '成都', '杭州']
for (let city in cites) {
  console.log(city)
}
  • for of迭代
const user = { name: 'wk', age: 40 }
for (const prop of user) {
  console.log(name)
}
  1. while循环
let i = 1
while (i < 10) {
  i++
}

2.4 函数

2.4.1 普通函数

函数的定义

function 函数名称(参数1: 参数1类型[, …]): 返回值类型 {

}

示例

function sayHello(name: string): string {
    return 'Hello'
}

可选参数函数,参数后跟一个?号,表示该参数可有可无

function sayName(name?: string): string {
    name = name ? : 'wk'
    return name
}

参数默认值函数

function sayName(name: string = 'wk') {
    return name
}

2.4.2 箭头函数

箭头函数定义

let 函数变量 = (参数1: 参数1类型[, …]) => {

}

示例:

let sayHi = (ret: string) => {
    return 'Hello'
}

2.5 命名空间

命名空间一个最明确的目的就是解决重名问题。命名空间定义了标识符的可见范围,一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。
命名空间语法:

namespace MyNameSpace { 
    export interface ISomeInterfaceName {}  
    export class SomeClassName {}  
}

以上定义了一个MyNameSpace的命名空间,如果我们需要在外部调用MyNameSpace命名空间中的类和接口,则需要在类和接口添加 export 关键字,要在另外一个命名空间调用语法格式为:

命名空间名.类名

如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:

/// <reference path = "SomeFileName.ts" />

以下演示定义在不同文件中命名空间的使用:

IShape.ts 文件代码:

namespace Drawing { 
    export interface IShape { 
        draw(); 
    }
}

Circle.ts 文件代码:

namespace Drawing { 
    export class Circle implements IShape { 
        public draw() { 
            console.log("Circle is drawn"); 
        }  
     }
}

Triangle.ts 文件代码:

namespace Drawing { 
    export class Triangle implements IShape { 
        public draw() { 
            console.log("Triangle is drawn"); 
        } 
     } 
}

TestShape.ts 文件代码:

function drawAllShapes(shape: Drawing.IShape) { 
  shape.draw(); 
} 
drawAllShapes(new Drawing.Circle());
drawAllShapes(new Drawing.Triangle());

2.6 面向对象

2.6.1 类

类定义

方式一

class 类名 {

    /**
     * 1. 属性前加static为类属性
     * 2. 属性前不加static为实例属性
     */
    [修饰符][static] 属性名: 类型

    constructor(参数: 类型) {
        this.属性名 = 参数;
    }

    /**
     * 1. 方法前加static为类方法
     * 2. 方法前不加static为实例方法
     */
    [static] 方法名(参数: 类型) {
        ......
    }

    // getter方法(方式一)
    get属性名() {
        return this.属性名;
    }

    /**
     * getter方法(方式二)
     *  调用 类对象.属性名    例如: person.name
     */
    get 属性名() {
        return this.属性名;
    }

    set属性名(value: 属性类型) {
        this.属性名 = value
    }

    /**
     * setter方法(方式二)
     *  调用 类对象.属性名 = value    例如: person.name = 'wk'
     */
    set 属性名(value: 属性类型) {
        this.属性名 = value
    }
}

属性的修饰符

  • public: 修饰的属性可以在任意地方修改,该值为默认值。

  • protected:只能在当前类和当前类的子类中访问。

  • private: 私有属性只能在类的内部修改。

方式二

class 类名称 {
    constructor(<属性修饰符> 属性名: 属性类型) {    
    }
}

类继承

class 类名 extends 父类 {
    /**
     * 1. 属性前加static为类属性
     * 2. 属性前不加static为实例属性
     */
    [static] 属性名: 类型

    constructor(参数: 类型) {
        this.属性名 = 参数;
    }

    /**
     * 1. 方法前加static为类方法
     * 2. 方法前不加static为实例方法
     */
    [static] 方法名(参数: 类型) {
        ......
    }

}

使用继承后,子类将继承父类的所有属性和方法

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    sayHello() {
        console.log('动物叫')
    } 
}

class Dog extends Animal {
    age: number;

    constructor(name: string, age: number) {
        // 子类中必须调用父类的构造函数
        super(name);
        this.age = age;
    }

    /**
     * 同名方法重写
     */
    sayHello() {
        console.log('汪汪')
    }

}

2.6.2 抽象类

在class前添加abstract关键字,该类就变成了抽象类。抽象类不能被用来创建对象,可以被继承。

abstract class Animal {

    /**
     * 抽象方法,子类必须对抽象方法进行重写
     */
    abstract sayHello(): void

}

2.6.3 接口

接口用来定义一个类的结构,包含哪些属性、方法。接口也可以当作类型声明来使用。接口是可以重复定义的,对多个接口取并集即为接口的整体定义。接口中的属性不能有实际值。

接口的定义

interface 接口名称 {
    属性名: 属性类型

    方法名(参数名: 参数类型): 返回值
}

接口的实现

class 类名称 implements 接口名称 {
    属性名: 属性类型

    constractor(属性名: 属性类型) {
        this.属性名 = 属性名
    }

    方法名(参数名: 参数类型): 返回值 {

    }
}

2.6.4 泛型

定义类或函数时,当不确定类型时可以使用泛型。

定义泛型函数

function fn<T>(参数: T): T {
}

泛型函数的调用

// 方式一,不指定泛型类型,由程序自动推断
fn(10)
// 方式二,强制指定泛型类型
fn<string>('hello')

定义多个泛型函数

function fn<T, K>(参数1: T, 参数2: K): T {
}

多个泛型函数的调用

fn<number, string(1, 'wk')

带继承的泛型

// 泛型 T 实现了接口 P 或者 继承了类 P
function fn<T extends P>(a: T): number {
}

定义类

class 类名<T> {
} 

2.7 声明文件

在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript诸如类型检查等特性功能。为了解决这个问题,需要将这些库里的函数和方法体去掉后只保留导出类型声明,而产生了一个描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。
假如我们想使用第三方库,比如 jQuery,我们通常这样获取一个 id 是 foo 的元素:

$('#foo');
// 或
jQuery('#foo');

但是在 TypeScript 中,我们并不知道 $ 或 jQuery 是什么东西,这时我们需要使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对。

declare var jQuery: (selector: string) => any;
jQuery('#foo');

declare 定义的类型只会用于编译时的检查,编译结果中会被删除。上例的编译结果是:jQuery(‘#foo’);

声明文件

声明文件以 .d.ts 为后缀,例如:runoob.d.ts,声明文件或模块的语法格式如下:

declare module Module_Name {
}

TypeScript 引入声明文件语法格式:

/// <reference path = " runoob.d.ts" />

当然,很多流行的第三方库的声明文件不需要我们定义了,比如 jQuery 已经有人帮我们定义好了:jQuery in DefinitelyTyped。
以下定义一个第三方库来演示:
CalcThirdPartyJsLib.js 文件代码:

var Runoob;  
(function(Runoob) {
  var Calc = (function () { 
  function Calc() { 
  } 
})
Calc.prototype.doSum = function (limit) {
 var sum = 0;
 for (var i = 0; i <= limit; i++) { 
    sum = sum + i; 
 }
 return sum; 
}
Runoob.Calc = Calc; 
return Calc;
})(Runoob || (Runoob = {})); 
var test = new Runoob.Calc();

如果我们想在 TypeScript 中引用上面的代码,则需要设置声明文件 Calc.d.ts,代码如下:
Calc.d.ts 文件代码:

declare module Runoob { 
    export class Calc { 
        doSum(limit:number): number; 
    }
}

声明文件不包含实现,它只是类型声明,把声明文件加入到 TypeScript 中:
CalcTest.ts 文件代码:

/// <reference path = "Calc.d.ts" /> 
var obj = new Runoob.Calc(); 
// obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));

下面这行导致编译错误,因为我们需要传入数字参数:

obj.doSum("Hello");

使用 tsc 命令来编译以上代码文件:

tsc CalcTest.ts

生成的 JavaScript 代码如下:
CalcTest.js 文件代码:

/// <reference path = "Calc.d.ts" /> 
var obj = new Runoob.Calc();
//obj.doSum("Hello"); // 编译错误
console.log(obj.doSum(10));

最后我们编写一个 runoob.html 文件,引入 CalcTest.js 文件及第三方库 CalcThirdPartyJsLib.js

<html>
  <head>
    <meta charset="utf-8">
    <title>教程</title>
    <script src="CalcThirdPartyJsLib.js"></script> 
    <script src="CalcTest.js"></script> 
  </head>
  <body> 
     <h1>声明文件测试</h1>
  </body>
</html>

三、TypeScript编译

3.1 配置文件

TypeScript的配置文件是tsconfig.json

tsconfig.json

{
    // 指定编译的目录 ** 任意目录, * 任务文件。默认编译所有文件
    "include": ["./src/**/*"],

    // 指定编译排除的目录。默认值:"node_modules", "bower_components", "jspm_packages"
    "exclude": ["node_modules"],

    // 定义被继承的配置文件,当前配置文件会包含config/base配置文件的内容
    // "extends": "./config/base"

    // 指定被编译的文件列表(只有需要编译的文件为少数时才会用到)
    // "files": [
    //     "core.ts"
    // ]

    // 编译器选项
    "compilerOptions": {
        // ts编译的目标版本。可选值:ES3(默认值), ES5, ES6/ES2015, ES2016, ES2017, ES2018, ES2019, ES2020, EXNext
        "target": "ES2015",
        /*
         * 指定代码运行时所包含的库(宿主环境)。
         * 可选值:ES5, ES6/ES2015, ES2016, ES2017, ES2018, ES2019, ES2020, EXNext, DOM, WebWorker, ScriptHost, ...
         */
        "lib": ["ES2015", "DOM"],
        // 指定编译后使用的模块化系统。可选值:None, CommonJS, UMD, AMD, System, ES6(ES2015), ES2020, ES2022, ESNext, Node16, NodeNext
        "module": "ES2015",
        // 指定编译后生成文件的目录。默认和源文件在同一目录
        "outDir": "./dist",
        // 将编译的代码合并为一个文件。注意:只有module值为amd, system时才支持
        // "outFile": "./dist/main.js"
        // 是否对指定编码目录下的js文件进行编译。默认为false,即编译后是否在输出目录生成js文件对应的文件。
        "allowJs": true,
        // 是否检查js文件是否符合语法规范。默认false
        "checkJs": true,
        // 编译后是否移除注释
        "removeComments": true,
        // 是否不生成编译后的文件(当仅仅验证是否能够编译成功,不需要生成编译后的文件时使用)。默认:true
        "noEmit": false,
        // 当编译有错误的时候是否生成编译文件。默认false
        "noEmitOnError": true,
        // 是否打开严格模式,如果打开了,其下的alwaysStrict, noImplicitAny, noImplicitThis, strictNullChecks都打开了
        "strict": true,
        // 指定编译后的文件是否使用严格模式。默认true
        "alwaysStrict": true,
        // 当变量不指定类型时,类型默认不为any
        "noImplicitAny": true,
        // 不允许使用隐士的this
        "noImplicitThis": true,
        // 严格的检查空值
        "strictNullChecks": true,        
    }

}
  1. 编译TypeScript

1)创建hello.ts

2)编译

# 编译成功后会在生成 hello.js
tcs hello.ts

编译参数

  • -w 监视文件的变化,如果文件有变化,则对文件进行编译

    tsc app.ts -w
    

四、WebPack打包

创建一个项目目录 demo-project

  1. 初始化npm
npm init -y

会在项目根目录生成package.js配置文件

{
  "name": "demo-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
  1. 安装webpack
npm install -D webpack webpack-cli

如果安装失败可用换用cnpm安装

webpack.config.js配置文件

在项目根目录创建webpack.config.js配置文件

// 引入path模块,用于拼接路径
const path = require('path')

// webpack配置信息
module.exports = {
    // 开始模式 development 或 production
    mode: "production",
    // 入口文件
    entry: "./src/index.ts",

    // 打包路径
    output: {
        // 指定打包文件目录
        path: path.resolve(__dirname, 'dist'),
        // 指定打包后的文件
        filename: 'bound.js'
    },

    // 指定webpack打包时要使用的模块
    module: {
        // 指定要加载的规则
        rules: [
            {
                // 匹配以.ts结尾的文件
                test: /\.ts$/,
                // 使用ts-loader进行加载
                use: 'ts-loader',
                // 要排除的文件
                exclude: /node-modules/
            }
        ]
    },

    // 配置哪些文件可用当作模块来使用
    resolve: {
        extensions: ['.ts', '.js']
    }
}

注意:因示例中使用了ts,因此还需要安装ts-laoder

npm install -D ts-loader
  1. TypeScript配置文件

在根目录创建TypeScript的配置文件tsconfig.js

tsconfig.js

{
    "compilerOptions" {
        "module": "ES2015",
        "target": "ES2015",
        "strict": true
    }
}
  1. 在package.js的script中添加build指令
"scripts": {
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
}
  1. 执行build命令
npm run build
  1. 安装webpack插件
  • html-webpack-plugin

    该插件会自动生成一个html页面,并引入生成的js文件。

    安装命令:

    npm install -D html-webpack-plugin
    

    在webpack.config.js中配置

    // 引入htmlWebPackPlugin
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
    // webpack配置信息
    module.exports = {
        // 配置webpack插件
        plugins: [
            new HtmlWebpackPlugin({
                title: '首页', // 页面title
                filename: 'index.html' // 生成的文件名
                template: path.resolve(__dirname, 'src/index.html'), // 模板文件的绝对路径
            })
        ]
    })
    
  • webpack-dev-server

    安装

    npm install -D webpack-dev-server
    

    在package.json的script中添加启动脚本

    "scripts": {
       "start": "webpack serve --open"
    }
    
  • clean-webpack-plugin

    npm install -D clean-webpack-plugin
    

    在webpack.config.js中配置

    // 引入clean-webpack-plugin
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    
    // webpack配置信息
    module.exports = {
        // 配置webpack插件
        new CleanWebpackPlugin()
    })
    
  • babel

    安装

    npm install -D @babel/core @babel/preset-env babel-loader core-js
    

    在webpack.config.js中配置

    // webpack配置信息
    module.exports = {
    
        // 指定webpack打包时要使用的模块
        module: {
            // 指定要加载的规则
            rules: [
                {
                    // 配置loader
                    use: [
                        // 配置babel
                        {
                            // babel加载器
                            loader: "babel-loader",
                            // 设置babel
                            options: {
                                // 设置预定义环境
                                presets: [
                                    [
                                        // 指定环境插件
                                        "@babel/preset-env",
                                        // 配置信息
                                        {
                                            // 要兼容的目标浏览器
                                            targets: {
                                                "chrome": "88"
                                            },
                                            // 指定corejs的版本
                                            "corejs": "3",
                                            // 使用corejs的方式: "usage"按需加载
                                            "useBuiltIns": "usage"
                                        }
                                    ]
                                ]
                            }
                        },
                        // 使用ts-loader进行加载
                        'ts-loader'
                    ],
                    // 要排除的文件
                    exclude: /node-modules/
                }
            ]
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值