typescript简介
- 以JavaScript为基础构建的语言
- 可以在任何支持JavaScript的平台中执行
- 一个JavaScript的超集
- TypeScript扩展了JavaScript,并添加了类型
- TS不能被JS解析器直接执行
typeScript增加了 - 支持ES的新特性
- 类型
- 添加ES不具备的新特性
- 丰富的配置选项
- 强大的开发工具
类型
// 字面量,相当于常量
let a: 10;
a = 10;
a = 11;
// 可以使用|
来连接多个类型
let b1: "male" | "female";
b1 = "male";
b1 = "female";
let c: boolean | string;
c = true;
c = "hello";
// any 表示的是任意类型,使用ts时不建议使用any类型,声明变量如果不指定类型,则ts解析器会自动判断变量的类型为
any(隐式的any)
let d: any;
d = "hello";
d = 10;
d = true;
// unknown 表示未知类型
let e: unknown;
e = 10;
e = "hello";
e = true
// unknown 实际上是一个类型安全的any
// unknown类型的变量不可以直接赋值给其他变量
// 赋值时需要先检查类型
let s: string;
// d的类型是any,他可以赋值给任意类型的变量
s = d;
// unknown 实际上是一个类型安全的any
// unknown类型的变量不可以直接赋值给其他变量
// 赋值时需要先检查类型
s = e;
if (typeof e === "string") {
s = e;
}
// 类型断言,可以用来告诉解析器变量的实际类型
- 语法:
- 变量 as 类型
- <类型>变量
s = e as string;
// void 用来表示空,就表示没有返回值
function fn(): void {
}
// never 表示永远不会有返回结果
function fn2(): never {
throw new Error("报错了!!")
}
// object表示一个js对象
let a: object;
a = {}
a = function () {
}
// {} 用来指定对象中可以包含哪些属性
// 语法:{属性名:属性值,属性名:属性值}
// 在属性名后加上?
,表示属性是可选的
let b2: { name: string, age?: number }
b2 = {
name: "haha", age: 12
}
//[propName:string]:any
表示任意类型的属性
let c1: { name: string, [propName: string]: any };
c1 = {
name: "aa", a: 1, b: 2
}
// 设置函数结构的类型声明
let d1: (a: number, b: number) => number;
d1 = function (n1, n2) {
return n1 + n2
}
- 数组的类型声明:
类型[]
Array<类型>
// string[]表示字符串数组
let e1: string[];
e1 = ['x', 'c', 'v'];
// number[]表示数值数组
let f: number;
let g: Array<number>;
g = [1, 2, 3]
// 元组,元组就是固定长度的数组
// 语法:[类型,类型,类型]
let h: [string, number];
h = ['hello', 123];
// enum 枚举
enum Gender {
Male = 0,
female = 1
}
let i: { name: string, gener: Gender };
i = {
name: 'zpp',
gener: Gender.Male
}
// &表示同时
let j: { name: string } & { age: number };
j = { name: "zpp", age: 18 };
// 类型别名
type myType = 1 | 2 | 3 | 4 | 5;
let k: myType;
let l: myType;
k = 2;
- 类型
类型 | 例子 | 描述 |
---|---|---|
number | 1,-33 | 任意数字 |
string | ‘a’,‘v’ | 任意字符串 |
boolean | true,false | 布尔值true或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined) | 没有值(或undefined) |
never | 没有值 | 不能是任何值 |
object | {name:“aa”} | 任意的js对象 |
array | [1,2,3] | 任意的js数组 |
tuple | [1,4] | 元组,ts新增类型,固定长度的数组 |
enum | enum{A,B} | 枚举,ts中新增类型 |
编译
tsc app.ts -w //自动监视,在文件改变的时候进行编译
配置选项
tsconfig.json 是ts编译器的配置文件,ts编译器可以根据他的信息来对代码进行编译
- include
- 哪些ts文件需要被编译
- 默认值
["**/*"]
,**
任意目录*
任意文件 - 实例:
"include": ["./src/**/*" ],
- “exclude”
- 不需要被编译的文件目录
- 默认值:[“node_modules”,“bower_components”,“jspm_packages”]
- “extend”
- 定义被继承的文件
- "files”
- 指定被编译文件的列表,只有需要编译的文件少是才会用到
- 示例
"files":[
"score.ts",
"sys.ts",
"type.ts"
]
- “compilerOptions”
- 编译选项
"compilerOptions": {
// target 用来指定ts被编译为的ES的版本
// 'es3 ','es5','es6 ' , 'es2015', 'es2016 ' , 'es2017', 'es2018', 'es2019', 'es2020' , 'esnext'
"target": "ES3",
// module 指定要使用的模块化规范
"module": "system",
// lib用来指定项目中要是用的库
// "lib": [],
// outDir 用来指定编译后文件所在的目录
"outDir": "./dist",
// 将代码合并成一个文件
// 设置motFile后,所有的全局作用域中的代码会合并到同一个文件中
"outFile": "./dist/app.js",
// 是否对js文件进行编译,默认所示false
"allowJs":false,
// 是否检查js代码是否符合语法规范,默认是false
"checkJs":false,
// 是否一处注释
"removeComments":false,
// 不生成编译后的文件
"noEmit":false,
// 当有错误时不生成编译后的文件
"noEmitOnError":true,
// 所有严格检查的【总开关】 以下4个都会打开
"strict":true,
// 用来设置编译后的文件是否使用严格模式,默认false
"alwaysStrict":true,
// 不允许隐式的any类型
"noImplicitAny":true,
// 不允许不明确类型的this
"noImplicitThis":true,
// 严格的检查空值
"strictNullChecks":true,
}
使用webpack打包ts代码
- 初始化项目
在项目中使用npm init -y
命令生成package.json文件 - 下载构建工具
cnpm i -D webpack webpack-cli typescript ts-loader
- 配置webpack.config.js文件
const path = require('path')
//
module.exports = {
// 指定入口文件
entry: "./src/index.ts",
// 指定打包文件所在的文件
output: {
path: path.resolve(__dirname, 'dist'),
filename:"bundle.js"
},
// 指定webpack打包时要用的模块
module: {
// 指定要加载的规则
rules: [
{
// test指定的是规则生效的文件
test: /\.ts$/,
// 要是用的loader
use: 'ts-loader',
// 指定要排除的文件
exclude:/node_modules/
}
]
}
}
- 配置tsconfig.json文件
{
"compilerOptions": {
"module": "ES2015",
"target": "ES2015",
"strict": true
}
}
- 修改package.json
- 使用npm run build 进行打包
- 自动生成HTML
安装
cnpm i -D html-webpack-plugin
引入
const HtmlWebpackPlugin = require('html-webpack-plugin')
配置webpack插件
// 配置webpack插件
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
}),
]
npm run build
- 自动打开实时更新网页
安装
cnpm i -D webpack-dev-server
在package.json中配置
"start": "webpack serve --open chrome.exe"
npm start
- 清除之前生成的打包文件
安装
cnpm i -D clean-webpack-plugin
引入
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
配置webpack插件
new CleanWebpackPlugin(),
- 配置引入模块
在webpack.config,js中配置
// 用来设置引用模块
resolve: {
extensions: ['.ts', '.js']
}
- 其他配置
安装
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
// 指定要加载的规则
rules: [
{
// test指定的是规则生效的文件
test: /\.ts$/,
// 要是用的loader
use: [
{
// 指定加载器
loader: 'babel-loader',
// 设置babel
options: {
//设置预定义的环境
presets: [
[
// 指定环境的插件
"@babel/preset-env",
//配置信息
{
// 要兼容的目标浏览器
targets: {
"chrome": "58",
"ie": "11"
},
// 指定corejs的版本
"corejs": "3",
// 使用corejs的方式
"useBuiltIns": "usage"
}
]
]
}
},
'ts-loader'
],
不使用箭头函数
output: {
path: path.resolve(__dirname, 'dist'),
filename: "bundle.js",
// 告诉webpack不能使用箭头
environment: {
arrowFunction: false
}
},
面向对象
类的简介
-
直接定义的属性是实例属性,需要通过对象的实例去访问:
const per = new Person();
per.name -
使用static开头的属性是静态属性,可以直接通过类对访 问
Person.age -
readonly开头的属性表示一个只读的属性无法修改
// 使用class关键字来定义一个类
class Person {
// 定义实例属性
name: string = "zpp";
// age: number = 18;
// 在属性前使用static关键字可以定义类属性(静态属性)
// static age: number = 18;
static readonly age: number = 18
// 定义方法
// 如果方法以static开头则是类方法,不实例就可以使用
sayHello() {
console.log("Hello")
}
}
const per = new Person();
console.log(per)
console.log(Person.age)
构造函数
class Dog {
name: string;
age: number;
// constructor 被称为构造函数
// 构造函数会在对象创建时调用
constructor(name: string, age: number) {
// 在实例方法中,this就表示当前的实例
// 在构造函数中当前对象就是当前新建的那个对象
// 可以通过this向新建的对象中添加属性
this.name = name;
this.age = age
console.log(this);
}
bark() {
alert("汪汪汪")
// 在方法中可以通过this来表示当前调用方法的对象
console.log(this.name)
}
}
const dog = new Dog("xiaog", 12)
console.log(dog)
继承
// 定义一个Animal类
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log("动物叫")
}
}
/**
* - 此时,Animal被称为父类,Dog被称为子类
- 使用继承后,子类将会拥有父类所有的方法和属性
- 通过继承可以将多个类中公有的代码卸载一个父类照片那个
这样只需要写一次即可让所以的子类都同时拥有父类的属性
如果希望在子类中添加一些父类中没有的属性或方法直接加就可以
- 如果在子类中添加了和父类相同的方法,则子类方法会覆盖掉父方法
这种子类覆盖掉父类方法的形式,我们称为方法重写
*/
class Dog extends Animal {
}
class Cat extends Animal {
sayHello() {
console.log("miao")
}
}
const dog = new Dog("wang", 5)
dog.sayHello();
const cat = new Cat("miao", 3)
cat.sayHello()
super
super 表示当前类的父类,如果在子类中写了构造函数,在子类的构造函数中必须调用父类的构造函数
抽象
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
// 定义一个抽象方法
// 抽象方法使用abstract开头,没有方法体
// 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract sayHello(): void
}
class Dog extends Animal {
sayHello() {
console.log("wang")
}
}
接口
// 描述一个对象的类型
type myType = {
name: string,
age: number,
// [propname: string]: any
}
const obj: myType = {
name: 'sss',
age: 111
}
// 接口用来定义一个类的结构,用来定义一个类中应该包含哪些属性和方法
// 同时接口可以当成类型声明去使用
interface myInterface {
name: string;
age: number;
}
interface myInterface{
gender: string;
}
const obj1: myInterface = {
name: 'sss',
age: 111,
gender:"male"
}
// 接口可以在定义类的时候去现在类的结构
// 接口中的所有属性都不能有实际的值
// 接口只能定义对象的结构,而不考虑实际值
// 在接口中所有的方法都是抽象方法
interface myINter {
name: string;
sayHello(): void;
}
/**
* 定义类时,可以使类去实现一个接口,
* 实现接口就是满足接口的需求
* */
class myClass implements myINter {
name: string;
constructor(name: string) {
this.name = name
}
sayHello(): void {
throw new Error("Method not implemented.")
}
}
属性的封装
public 修饰的属性可以在任意位置访问(修改)默认值
private 私有属性,私有属性只能在类内部进行访问(修改)
class Person {
private _name: string;
private _age: number;
constructor(name: string, age: number) {
this._name = name;
this._age = age;
}
// getter 用来读取属性
// setter 方法用来设置属性
get name() {
return this._name;
}
get age() {
return this._age;
}
set name(value) {
this._name = value;
}
set age(value) {
if (value >= 0) {
this._age = value;
}
}
}
const per = new Person('zpp', 18);
console.log(per)
console.log(per.name)
per.name = "1234"
console.log(per.name)
protexted 受保护的属性,只能在当前类的子类中访问(修改)
class A {
protected num: number;
constructor(num:number) {
this.num =num
}
}
class B extends A {
test() {
console.log(this.num)
}
}
简单写法,语法糖
class C {
constructor(public name: string, public age: number) {
}
}
const c = new C("xxx", 12)
console.log(c)
泛型
(function () {
// 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
function fn<T>(a: T): T {
return a;
}
let result = fn(10); // 不指定泛型,TS可以自动对类型进行推断
let result1 = fn<string>("123"); // 指定泛型
//泛型可以同时指定多个
function fn2<T, K>(a: T, b: K): T {
return a;
}
fn2<number, string>(13, "zpp");
interface Inter {
length: number;
}
// T extends Inter 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T): number {
return a.length;
}
fn3("123")
fn3({ name: "zpp", length: 123 })
class MyClass<T> {
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new MyClass<string>('zpp')
})()