开发环境搭建
- 安装Node.js
- 使用npm全局安装typescript
进入命令行,输入npm i -g typescript
- 创建一个ts文件
- 使用tsc对ts文件进行编译
- 进入命令行
- 进入ts文件所在目录
- 执行命令ts xxx.ts
1.TS的类型声明
unknown
实际上就是一个类型安全的any
;
unknown
类型的变量,不能直接赋值给其他变量
/*
{}用来指定对象中可以包含哪些属性
语法 {属性名:属性值}
在属性名后加上?表示属性是可选的 */
let a :{name:string,age?:number};
a = {name:"lili"};
********************************************************
// ### 01 定义对象结构
// [propName:string]:any 表示任意类型的属性
let b:{name:string, [propName:string]:any};
b = {name:"lili",age:18,gender:"女"}
********************************************************
/* ### 02 定义函数结构
设置函数结构的类型声明语法:
(形参:类型,形参:类型...) => 返回值
*/
let c :(a:number, b:number) => number;
c = function(n1,n2):number {
return n1+n2;
}
********************************************************
/*
### 03 数组的类型声明:
类型[]
Array<类型>
*/
let d : string[];
d = ["a","b","c"];
let e :Array<number>;
e = [1,2,3];
********************************************************
/*
### 04 元组就是固定长度的数组
语法:[类型,类型,类型]
*/
let f :[string,number];
f = ["hello",123]
********************************************************
/*
### 05 enum 枚举
*/
enum Gender {
Male,
Female
}
let g :{name:string,gender:Gender};
g ={
name:"lili",
gender:Gender.Male // "male"
}
&逻辑与
// &表示同时拥有两个参数
let h:{name:string} & {age:number};
h = {name:"lili",age:18}
类型的别名
//适用于类型特别复杂的情况,简化类型的使用
type myType = 1|2|3|4|5;
let i :myType;
2.TS的编译选项
配置tsconfig.json
文件
{
/*
tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息对代码进行编译
*/
// ### 01 "include"用来指定哪些ts文件需要被编译
"include":[
"./src/**/*" // src任意目录下的任意文件
],
// ### 02 "exclude" 不需要被编译的文件目录,
// 默认值:["node_modules","bower_components","jspm_packages"]
"exclude":[
"./src/hello/**/*"
],
// ### 03 "extends" 定义被继承的配置文件
"extends":"",
// ### 04 "files" 指定被编译文件的列表,只有需要编译文件数量少时才会用到
"files:[
"core.ts",
...
],
// ### 04 "compilerOptions" (重点)
// 编译选项是配置文件中非常重要也比较复杂的配置选项,包含多个子选项
"compilerOptions":{
"target":"es6", // 用来指定ts被编译为的ES版本
"module":"es2015", // 指定要使用的模块化规范
"lib":["dom"], // 指定项目中要使用的库,一般不需要设置
"outDir":"./dist", // 指定编译后文件所在的目录
"outFile":"./dist/app.js", // 将所有全局作用域中的代码合并到一个文件中,如果想要合并模块("module":"system")
"allowJs":false, //是否对js文件进行编译。默认为false
"checkJs":false, // 是否检查js代码是否符合语法规范,默认为false
"removeComments":false, // 是否移除注释
"noEmit":true, // 是否生成编译后的文件
"noEmitOnError":true, // 当有错误时不生成编译后文件
"strict":false, //所有严格检查的总开关
"alwaysStrict":false, // 编译后的文件是否使用严格模式,默认为false
"noImplicitAny":true, // 不允许隐式的any类型
"noImplicitThis":true, // 不允许不明确类型的this
"strictNullChecks":true, // 严格地检查空值
}
}
在命令行输入tsc(或者tsc -w:监视所有文件)就可以实现ts编译了
3.使用webpack打包ts代码
-
对项目进行初始化 (生成package.json文件);
npm init -y
-
安装webpack所需依赖;
cnpm i -D webpack webpack-cli typescript ts-loader
,
其他优化的依赖:
cnpm i -D html-webpack-plugin
——自动生成html文件,
cnpm i -D webpack-dev-server
——项目里面安装内置服务器,热刷新,
cnpm i -D clean-webpack-plugin
——生成新文件前清空dist文件夹,
cnpm i -D @babel/core @babel/preset-env babel-loader core-js
——生成不同版本文件,解决浏览器兼容性问题 -
编写webpack配置文件webpack.config.js;
// 引入一个包
const path = require("path");
// 引入html插件
const HTMLWebpackPlugin = require("html-webpack-plugin");
// 引入clean插件
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
// Webpack中的所有配置信息都应该写在module.exports中
module.exports = {
entry:"./src/index.ts", // 指定入口文件
// 指定打包文件所在目录
output: {
path:path.resolve(__dirname,"dist"), // 路径
filename:"bundle.js" // 打包后文件的名字
// 告诉webpack不使用箭头函数(兼容ie的情况)
environment:{
arrowFunction:false
}
},
// 指定webpack打包时要使用的模块
module: {
// 指定要加载的规则
rules: [
{
test:/\.ts$/, //指定规则对哪些文件生效
use:[
// 配置babel
{
// 指定加载器
loader:"babel-loader",
// 设置babel
options:{
// 设置预定义的环境
presets:[
[
// 指定环境的插件
"@babel/preset-env",
// 配置信息
{
// 要兼容的目标浏览器
target:{
"chrome":"58",
"ie":"11"
},
// 指定corejs的版本
"corejs":"3",
// 使用core.js的方式 "usage"表示按需加载
"useBuiltIns":"usage"
}
]
]
}
},
'ts-loader', //要使用的loader,从后往前执行
]
exclude:/node-modules/ //要排除的文件
}
]
},
// 配置Webpack插件
plugins:[
new CleanWebpackPlugin(),
new HTMLWebpackPlugin(options:{
// title:"这是一个自定义的title",
template:"./src/index.html", // 指定网页生成模板
}),
],
// 用来设置引用模块
resolve: {
extensions:[".ts",".js"] // 指定哪些文件可以作为模块使用
}
}
- 指定ts文件的编译规范 tsconfig.json;
- 往package.json文件中添加配置;
"scripts":{
"build":"webpack",
// 配置启动服务器
"start":"webpack serve --open chrome.exe"
}
- 执行编译命令;
npm run build
- 启动服务器查看;
npm start
4.面向对象简介
面向对象,简而言之就是程序之中所有的操作都需要通过对象来完成。
- 类的定义
// 使用class关键字来定义一个类
/*
类中主要包含了两个部分:
属性
方法
*/
class Person {
/*
直接定义的属性是实例属性,需要通过对象的实例去访问;
const per = new Person();
per.name
使用static开头的属性是静态属性(类属性),可以直接通过类去访问
Person.age
*/
// 定义属性(实例属性)
name:string = "lili";
// 在属性前使用static关键字可以定义类属性(静态属性)
static age:number = 18;
// 定义方法
sayHello() {
console.log("Hello!");
}
// 类方法
static sayHello2() {
console.log("Hello");
}
}
const per = new Person();
console.log(per.name);
// 静态属性通过类来访问
console.log(Person.age);
per.sayHello();
Person.sayHello2();
- 构造函数和this
class Dog{
name: string;
age: number;
// constructor 被称为构造函数
// 构造函数会在对象创建时调用
constructor(name:string,age:number) {
// 在实例方法中,this就表示当前的实例
// 在构造函数中当前对象就是当前新建的那个对象
// 可以通过this向新建的对象中添加属性
this.name = name;
this.age = age;
}
bark() {
// 在方法中可以通过this来表示当前调用方法的对象
console.log(this.name);
}
}
const dog1 = new Dog("小黑",4);
const dog2 = new Dog("小白",2);
dog1.bark();
- 继承和super
// 定义一个animal类
class Animal {
name: string;
constructor(name:string) {
this.name = name;
}
sayHello() {
console.log("动物在叫");
}
}
/*
使用继承后,子类会拥有父类所有的方法和属性;
通过继承可以将多个类中共有的代码写在一个父类中,避免代码的重复;
子类可以对父类中的方法进行拓展和重写;
子类中使用super关键字调用父类的方法;
*/
// 使Dog类继承Animal类
class Dog extends Animal{
age:number
constructor(name:string,age:number) {
// 如果在子类中写了构造函数,在构造函数中必须对父类的构造函数进行调用
super(name); // 调用父类的构造函数
this.age = age;
}
// 子类独有的方法
run() {
console.log("I`m running");
}
sayHello() {
// super表示当前类的父类
super.sayHello();
// console.log("汪汪!");
}
}
// 使Cat类继承Animal类
class Cat extends Animal{
sayHello() {
console.log("喵喵!");
}
}
const dog = new Dog("旺财",2);
const cat = new Cat("咪咪",3);
dog.run()
- 抽象类
/*
以abstract开头的类是抽象类,
抽象类是专门用来被继承的类,不能用来创建对象;
抽象类中可以添加抽象方法;
*/
abstract class Animal {
name: string;
constructor(name:string) {
this.name = name;
}
// 定义一个抽象方法
// 抽象方法使用 abstract 开头,没有方法体
// 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract sayHello():void;
}
- 接口
// 描述一个对象的类型
type myType = {
name:string,
age:number
};
/* ### 01
使用接口来定义一个类结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当成类型声明去使用;
*/
interface myInterface {
name:string,
age:number;
}
const obj:myType = {
name:"sss",
age:11
};
/* ### 02
接口可以在定义类的时候去限制类的结构;
接口中所有的属性都不能有实际的值,
接口只定义对象的结构,而不考虑实际值,
在接口中所有的方法都是抽象方法
*/
interface myInter {
name:string;
sayHello():void;
}
/*
定义类时,可以使类去实现一个接口,
实现接口就是使类满足接口的要求
*/
class MyClass implements myInter {
name: string;
constructor(name:string) {
this.name = name;
}
sayHello() {
console.log("hi");
}
}
- 属性的封装
// 封装:不参与直接修改属性,让数据更安全
class Person {
// TS可以在属性前添加属性的修饰符
/*
public 修饰的属性可以在任意位置访问(修改)默认值;
private 私有属性,只能在类内部进行访问(修改)
通过在类中添加方法使得私有属性可以被外部访问
protected 受保护的属性,只能在当前类及其子类中进行访问(修改0
*/
private _name: string;
private _age : number;
constructor(name:string,age:number) {
this._name = name;
this._age = age;
}
/*
getter 方法用来读取属性
setter 方法用来设置属性
它们被称为属性的存取器
*/
/* // 定义方法,用来获取name属性
getName() {
return this._name;
}
// 定义方法,用来设置name属性
setName(value:string) {
this._name = value;
}
getAge() {
return this._age;
}
setAge(value:number) {
if (value >= 0) {
this._age = value;
}
} */
// TS中设置getter方法的方式
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
get age() {
return this._age;
}
set age(value) {
if (value >= 0) {
this._age = value;
}
}
}
const per = new Person("lili",23);
// 外部获取
console.log(per.name);
per.age = -33;
***********************************************
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) {
}
}
- 泛型
// function fn(a:number):number {
// return a;
// }
/*
在定义函数或是类时,如果遇到类型不明确就可以使用泛型
*/
function fn<T> (a:T) : T {
return a;
}
// 可以直接调用具有泛型的函数
let result = fn(10); // 不指定泛型,TS可以自动对类型进行推断
let result2 = fn<string>("hello"); // 指定泛型
*****************************************************
// 定义多个泛型
function fn2<T,K>(a:T,b:K):T {
console.log(b);
return a;
}
*****************************************************
// 限制泛型的范围
interface Inter {
length :number;
}
// T extends Inter 表示泛型T必须是Inter的实现类(子类)
function fn3<T extends Inter>(a:T):number {
return a.length;
}
fn3( {length:10});
class MyClass<T> {
name:T;
constructor(name:T) {
this.name = name;
}
}
const mc = new MyClass<string>("lili");