1 开发环境搭建
npm i -g typescript
tsc xxx.ts
1.1 webpack配置
-
初始化项目
- 进入项目根目录,执行命令
npm init -y- 主要作用:创建package.json文件
- 进入项目根目录,执行命令
-
下载构建工具
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin @babel/core @babel/preset-env babel-loader core-js- 共安装了11个包
- webpack
- 构建工具webpack
- webpack-cli
- webpack的命令行工具
- webpack-dev-server
- webpack的开发服务器
- typescript
- ts编译器
- ts-loader
- ts加载器,用于在webpack中编译ts文件
- html-webpack-plugin
- webpack中html插件,用来自动创建html文件
- clean-webpack-plugin
- webpack中的清除插件,每次构建都会先清除目录
- @babel/core
- babel的核心工具
- @babel/preset-env
- babel的预定义环境
- @babel-loader
- babel在webpack中的加载器
- core-js
- core-js用来使老版本的浏览器支持新版ES语法
- webpack
- 共安装了11个包
-
根目录下创建webpack的配置文件webpack.config.js
-
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { optimization:{ minimize: false // 关闭代码压缩,可选 }, entry: "./src/index.ts", devtool: "inline-source-map", devServer: { contentBase: './dist' }, output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js", environment: { arrowFunction: false // 关闭webpack的箭头函数,可选 } }, resolve: { extensions: [".ts", ".js"]//ts模块化问题解决 }, module: { rules: [ { test: /.ts$/, use: [ { loader: "babel-loader", options:{ presets: [ [ "@babel/preset-env", { "targets":{ "chrome": "58", "ie": "11" }, "corejs":"3", "useBuiltIns": "usage"//按需加载 } ] ] } }, { loader: "ts-loader", } ], exclude: /node_modules/ } ] }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ //title:'TS测试' template:'./src/index.html' }), ] }
-
-
根目录下创建tsconfig.json,配置可以根据自己需要
-
{ "compilerOptions": { "target": "ES2015", "module": "ES2015", "strict": true } }
-
-
修改package.json添加如下配置
-
{ ...略... "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack", "start": "webpack serve --open chrome.exe" }, ...略... }
-
-
在src下创建ts文件,并在并命令行执行
npm run build对代码进行编译,或者执行npm start来启动开发服务器
1.2 编译选项
- 添加tsconfig.json配置文件
- 执行tsc -w,自动监视
{
/*
tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译
*/
"include": [
"./src/**/*" //路径:** 表示任意目录 * 表示任意文件
],
// "exclude": [
// "./src/hello/**/*" //默认值:["node_modules", "bower_components", "jspm_packages"]
// ]
/*
compilerOptions 编译器的选项
*/
"compilerOptions": {
// target 用来指定ts被编译为的ES的版本
// 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'
"target": "es2015",
// module 指定要使用的模块化的规范
// 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'esnext'
"module": "es2015",
// lib用来指定项目中要使用的库
//'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'es
//2018', 'es2019', 'es2020', 'esnext', 'dom', 'dom.iterable', 'webworker', 'webworker.importscripts', 'webworker.iterable', 'scri
//pthost', 'es2015.core', 'es2015.collection', 'es2015.generator', 'es2015.iterable', 'es2015.promise', 'es2015.proxy', 'es2015.r
//eflect', 'es2015.symbol', 'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object', 'es2017.sharedmemory', 'es2017.st
//ring', 'es2017.intl', 'es2017.typedarrays', 'es2018.asyncgenerator', 'es2018.asynciterable', 'es2018.intl', 'es2018.promise', '
//es2018.regexp', 'es2019.array', 'es2019.object', 'es2019.string', 'es2019.symbol', 'es2020.bigint', 'es2020.promise', 'es2020.s
//haredmemory', 'es2020.string', 'es2020.symbol.wellknown', 'es2020.intl', 'esnext.array', 'esnext.symbol', 'esnext.asynciterable
//', 'esnext.intl', 'esnext.bigint', 'esnext.string', 'esnext.promise', 'esnext.weakref'
"lib": ["es6", "dom"]
// outDir 用来指定编译后文件所在的目录
"outDir": "./dist",
// 设置outFile后,所有的全局作用域中的代码会合并到同一个文件中
"outFile": "./dist/app.js"
// 是否对js文件进行编译,默认是false
"allowJs": true,
// 是否检查js代码是否符合语法规范,默认是false
"checkJs": true,
// 是否移除注释
"removeComments": true,
// 不生成编译后的文件
"noEmit": false,
// 当有错误时不生成编译后的文件
"noEmitOnError": true,
// 所有严格检查的总开关,打开后相当于以下四个配置
"strict": true,
// 用来设置编译后的文件是否使用严格模式,默认false;es6模块化语法自动开启严格模式
"alwaysStrict": true,
// 不允许隐式的any类型
"noImplicitAny": true,
// 不允许不明确类型的this
"noImplicitThis": true,
// 严格的检查空值
"strictNullChecks": true
}
}
2 类型声明
2.1 基本类型
//number
let a: number=10;
//string
let b: string;
b = 'hello';
//boolean
//let c:boolean = false;
let c = false;
c = true;
//字面量
// 直接使用字面量进行类型声明
let a: 10;
a = 10;
// 可以使用 | 来连接多个类型(联合类型)
let b: "male" | "female";
b = "male";
b = "female";
let c: boolean | string;
c = true;
c = 'hello';
let names:(atring|number)[]=[123,'123'];
2.2 any和unknown
//any
let d: any;
// 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any (隐式的any)
let d;
d = 10;
d = 'hello';
d = true;
// unknown 表示未知类型的值
let e: unknown;
e = 10;
e = "hello";
e = true;
let s:string;
s = d;// d的类型是any,它可以赋值给任意变量
e = 'hello';
//s=e;//unknown 实际上就是一个类型安全的any,不能赋值给其他变量
if(typeof e === "string"){
s = e; //方式一
}
s = e as string; //方式二
s = <string>e; //方式三
2.3 void和never
// void 用来表示空,以函数为例,就表示没有返回值的函数,即return;
function fn(): void{
}
// never 表示永远不会返回结果,即报错
function fn2(): never{
throw new Error('报错了!');
}
2.4 对象和枚举
// object表示一个js对象:类型太多了
let a: object;
a = {};
a = function () { };
// 在属性名后边加上?,表示属性是可选的
let b: {name: string, age?: number};
b = {name: '孙悟空', age: 18};
let c: {name: string, [propName: string]: any};
c = {name: '猪八戒', age: 18, gender: '男'};
//枚举
enum Gender{
Male=0,
Female=1
}
let i: {name: string, gender: Gender};
i = {
name: '孙悟空',
gender: Gender.Male // 'male'
}
// console.log(i.gender === Gender.Male);
2.5 函数
//先声明后赋值
let d: (a: number ,b: number)=>number;
d = function (n1: string, n2: string): number{
return 10;
}
//声明加赋值
function sum(a: number, b: number): number{
return a + b;
}
let result = sum(123, 456);
//无返回值
function func(item: string): void{ }
2.6 数组和元组
// string[] 表示字符串数组
let e: string[];
e = ['a', 'b', 'c'];
// number[] 表示数值数值
let f: number[];
let g: Array<number>;
g = [1, 2, 3];
/*
* 元组,元组就是固定长度的数组
* 语法:[类型, 类型, 类型]
* */
let h: [string, number];
h = ['hello', 123];
2.7 符号
// &表示同时
let j: { name: string } & { age: number };
// j = {name: '孙悟空', age: 18};
// 类型的别名
type myType = 1 | 2 | 3 | 4 | 5;
let k: myType;
let l: myType;
let m: myType;
k = 2;
3 类
3.1 类的继承
// 定义一个Animal类
abstract class Animal{ //抽象类,只能被继承,不能来创建实例
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello(){
console.log('动物在叫~');
}
//abstract:sayHello():void;//抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
}
// 定义一个表示狗的类
class Dog extends Animal{
sex: number;
constructor(name: string, age: number, sex: number) {
super(name,age); // 调用父类的构造函数
this.sex = sex;
}
run(){//子类方法
console.log(`${this.name}在跑~~~`);
}
sayHello() {//重写父类的方法
console.log('汪汪汪汪!');
}
}
// 定义一个表示猫的类
class Cat extends Animal{
sayHello() {//重写父类的方法
console.log('喵喵喵喵!');
}
}
const dog = new Dog('旺财', 5);
const cat = new Cat('咪咪', 3);
console.log(dog);
dog.sayHello();
dog.run();
console.log(cat);
cat.sayHello();
3.2 属性的封装
- public属性
/* class C{
name: string;
age: number
// 可以直接将属性定义在构造函数中
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}*/
class C{
// 可以直接将属性定义在构造函数中:完成属性赋值和声明
constructor(public name: string, public age: number) { }
}
const c = new C('xxx', 111);
console.log(c);
- private属性
//1.private属性
class Person{
// TS可以在属性前添加属性的修饰符
/*
* public 修饰的属性可以在任意位置访问(修改)--默认值
* private 私有属性只能在类内部进行访问(修改)
* 通过在类中添加方法使得私有属性可以被外部访问
* protected 受保护的属性,只能在当前类和当前类的子类中访问(修改),子类的实例访问不到
*
* */
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(){
// console.log('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('孙悟空', 18);
//属性可以任意的被修改
// per.setName('猪八戒');
// per.setAge(-33);
per.name = '猪八戒';
per.age = -33;
console.log(per);
- protected属性
//2.protected属性
class A{
protected num: number;
constructor(num: number) {
this.num = num;
}
}
class B extends A{
test(){
console.log(this.num);
}
}
const b = new B(123);
// b.num = 33;//不能修改
4 接口
//1.接口可以当成类型声明去使用:描述一个对象的类型
type myType = {
name: string,
age: number
};
interface myInterface {
name: string;
age: number;
}
interface myInterface {
gender: string; //必选属性
color?:string;//可选属性
readonly x:number;//只读属性
[propName:string]:any;//额外的属性检查
}
const obj: myInterface = {
name: 'sss',
age: 111,
gender: '男'
};
type Person=myType|myInterface
//2.用来定义一个类中应该包含哪些属性和方法
interface myInter{
name: string;
sayHello():void;
}
class MyClass implements myInter{
name: string;
constructor(name: string) {
this.name = name;
}
sayHello(){
console.log('大家好~~');
}
}
5 泛型
/*
* 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
*
* */
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;
}
fn2<number, string>(123, 'hello');
//1.函数
interface Inter{
length: number;
}
// T extends Inter 表示泛型T必须时Inter实现类(子类)
function fn3<T extends Inter>(a: T): number{
return a.length;
}
//2.类
class MyClass<T>{
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new MyClass<string>('孙悟空');
6 keyof和typeof
const todo={
name:'xiaohong',
age:18,
gender:false
}
//keyof返回obj所有key的联合类型
type K=keyof todo;//'name'| 'age' | 'gender'
function prop<T,K extends keyof T>(obj:T,key:K){
return obj[key]
}
prop(todo,'name')
interface IPiont{
x:number;
y:number;
}
type Name<T>={ [P in keyof T]:T[P] };
type real=Name<IPiont>;//{x:number,y:number}
//typeof获取一个变量或对象的类型
const sem:IPiont={x:2,y:1}
type sem=typeof sem;//type sem=IPiont
function toArray(x:number):Array<number>{
return [x]
}
type Func=typeof toArray;//(x:number)=>number[]