类型声明
//number类型
let a : number;
a=10
//string类型
let b : string;
b='hello'
//boolean 声明变量直接赋值
//let c : boolean = true
//如果变量声明与赋值是同时进行,ts可以自动对变量进行类型检测
let c = true;
//function
function sum(a:number,b:number):number{
return a+b
}
sum(11,456)
//可以直接使用字面量进行类型声明 可以使用 | 连接多个类型
let a : 'red' | 'blue';//a只能被赋值为后面两个值
let c : boolean | string
c=true
c='hello'
//any 表示的是任意类型,一个变量设置any后相当于对该类型关闭了TS类型检测
let d :any;
d=true
d=111
//声明变量如果不指定类型,则TS解析器会自动判断变量类型为any (隐式any)
let d;
d=10
d='hello'
//unknown 表示未知类型的值
let e :unknown;
e=10
e='hello'
// d的值为any可以赋值给任意变量(并且会把自己赋值的变量的类型检测也给关了),但是unkonwn不行
let s:string;
//unknown实际上就是一个类型安全的any 不能直接赋值给其他变量
if(typeof e === "string"){
s=e;//不报错
}
//直接 s=e 报错
//类型断言
/*
*语法:
*变量 as 类型
*<类型>变量
*/
//也可以使用类型断言 类型断言,可以用来告诉解析器变量的实际类型
s=e as string; //类型断言 形式一
s=<string>e; //类型断言 形式二
//void 用来表示空,以函数为例,就表示没有返回值
function fn():viod{
}
//never 表示永远不会返回结果 一般函数没有返回值就返回undefined,但是有一种函数就是用来抛出错误,就没有任何返回值了
function fn2():never{
throw new Error('报错了!')
}
//object表示一个js对象 并没有什么作用,因为js中万物皆对象
let a: object;
a={};
a=function(){}
//所以声明对象可以用 {} 用来指定对象可以包含哪些属性
//语法 {属性名:属性值(类型)}
//属性名后面 ?: 表示该属性是可选的,可有可不有
//[propName:string]:any 表示可以有任意属性
let b:{name:string,age?:number};// ?: 表示该属性是可选的,可有可不有
b={name:'张三'}
let c: {name:string,[propName:string]:any}
c={name:'李四',age:18}
/*
* 设置函数结构的类型声明:
* 语法:(形参:类型,形参:类型 ...)=>返回值
*/
//字面量函数写法
let d: (a:number,b:number)=>number;
/*
*数组
* 类型[]
* Array<类型>
*/
//string[] 表示字符串数组
let e:string[];
//number[] 表示数值数组
let f: number[];
let g: Array<number> 与上述同义
/*
*元组,元组就是固定长度的数组
* 语法:
* [类型,类型,类型]
*/
let h:[string,string]
h=['aa','bb']
/*
*enum 枚举
* 语法:
*
*/
enum Gender{
Male = 0,
Female = 1
}
let i: {name:string,genter:Genter}
i={
name:'sun',
gender:Gender.Male
}
//&表示同时
let j: {name:string} & {age:number}
//j={name:'sun',age:18}
//类型别名
type myType = 1|2|3|4|5;
let k: myType;
k=5
类型 | 例子 | 描述 |
number | 1, -33, 2.599 | 任意数字 |
string | 'hi', "hello" | 任意字符串 |
boolean | true、false | 布尔值true或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值(undefined) | 没有值(或undefined) |
never | 没有值 | 不能是任何值 |
object | {name:'孙悟空'} | 任意的JS对象 |
array | [1,2,3] | 任意JS数组 |
tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
enum | enum{A, B} | 枚举,TS中新增类型 |
编译选项
自动监控编译
tsc xxx.ts -w
在一个文件夹下,创建 tsconfig.json 文件,在用命令 tsc 就可以自动编译当前文件夹下的ts文件
{
/*
tsconfig.json 是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译
"include" 用来指定哪些ts文件需要被编译
"exclude" 不需要被编译的文件目录
默认值:["node_modulex","bower_components","jspm_packages"]
"extends" 定义被继承的配置文件
"extends":"./config/base" 表示当前配置文件中会自动包含config目录下base.json中的所有配置信息
"files" 指定被编译文件的列表,只有需要编译的文件少时才会用到
"files":[
"core.ts",
"sys.ts",
"types.ts"
]
*/
"include":[
"./src/**/*" // *任意文件 **任意目录
],
"exclude":[
"./sr/hello/**/*"
],
/*
compilerOptions 编译器的选项
它决定了我们编译器如何去对我们这个ts文件进行编译
*/
"compilerOptions":{
//target 用来指定被编译的js版本
"target":"es2015", //esnest表示最新的es版本
//module 用来指定使用的模块规范
"module":"es2015", //CommonJS、UMD、AMD、System、ES2020、ESNext、None
//lib 用来指定项目中要使用的库
"lib":["dom"],
//outDir 用来指定编译后文件所在目录
"outDir":"./dist",
//outFile 将代码合并成一个文件,所有全局作用域中的代码会合并到同一个文件中
"outFile":"./dist/app.js",
//是否对js文件进行编译,默认是false
"allowJs":false,
//checkJs 是否检查js代码语法规范,默认是false
"checkJs":false,
//removeComments 是否移除注释,默认值false
"removeComments":true,
//noEmit 不对代码进行编译
"noEmit":false,
//当有错误的时候不生成编译文件
"noEmitOnError":false,
//sourceMap 是否生成sourceMap
"sourceMap":false,
//严格检查的总开关
"strict":false //如果是false表示以下所有的严格检查都关闭,true表示都开启
//用来设置编译后的文件是否使用严格模式,默认false
"alwayStrict":false,
//不允许隐式any类型
"noImplicitAny":true,
//不允许不明确类型的this
"noImplicitThis":false,
//严格检查空值
"strictNullChecks":true
}
}
webpack
使用webpack配置ts编写环境,需要先下载如下几个包
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin html-webpack-plugin
webpack.config.js
//引入一个有关路径的包
const path = require('path');
// 引入html插件
const HTMLWebpackPlugin = require("html-webpack-plugin")
// 引入每次打包之前先清除打包文件的插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
// webpack所有配置信息
module.exports={
optimization:{
minimize: false // 关闭代码压缩,可选
},
// 定义入口文件
entry:"./src/index.ts",
//此选项控制是否生成,以及如何生成 source map。
devtool: "inline-source-map",
devServer: {
contentBase: './dist'
},
// 指定打包文件所在目录
output:{
// 指定打包文件目录
path:path.resolve(__dirname,'dist'),
// 打包后文件的文件
filename:"bundle.js",
// 告诉webpack不使用箭头函数
environment:{
arrowFunction:false
}
},
// 用来设置引用模块
resolve: {
extensions: [".ts", ".js"]
},
// 指定webpack打包要使用模块
module:{
// 指定要加载规则
rules:[
{
//test 指定的是规则生效文件
test:/\.ts$/,
// 使用什么loader进行
use:[
//配置babel
{
// 指定加载器
loader:"babel-loader",
// 设置babel
options:{
// 设置预定义环境
presets:[
[
// 指定环境插件
"@babel/preset-env",
// 配置信息
{
// 要兼容的目标浏览器
targets:{
"chrome":"88",
"ie":"11"
},
// 指定corejs版本
"corejs":"3",
// 使用corejs的方式"usage" 表示按需加载
"useBuiltIns":"usage"
}
]
]
}
},
'ts-loader'
],
// 要排除的文件
exclude:/node-module/
}
]
},
// 配置webpack插件
plugins:[
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
// title:"这是一个自定义插件"
template:'./src/index.html'
}),
]
}
面向对象
类
//使用class关键字来定义一个类
//对象中主要包含两个部分:属性 方法
/*
直接定义的属性是实例属性,需要通过对象的实例去访问:
const per = new Person()
per.name
使用static开头的属性是静态属性(类属性),可以直接通过类去访问
Person.name
readonly开头的属性表示一个只读的属性无法修改
*/
class Person{
//定义实例属性
name:string = '孙悟空';
//在属性前使用static关键字可以定义类属性(静态属性)
static age:number = 18;
//定义方法
sayHello(){
console.log('hello,大家好')
}
}
const per = new Person();
console.log(per.name)
构造函数
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);
}
}
继承 super
class Animal{
name:string;
age:number;
constructor(name:string,age:number){
this.name=name
this.age=age
}
bark(){
console.log('动物在叫');
}
sayHello(){
console.log('说你好');
}
}
// dog继承animal
/*
-此时dog被称为子类 animal被称为父类
-使用继承后,子类将会拥有父类所有的方法和属性
-通过继承可以将多个类中共有的代码写在一个父类中
这样只需要写一次即可让所有子类都同时拥有父类中的属性和方法
如果希望在子类中添加一些父类中没有的属性或方法直接加就行
-如果在子类中添加了和父类相同的方法,则子类的方法会覆盖父类的方法
这种子类覆盖父类的方法,我们称为方法重写
*/
class Dog extends Animal{
sound:string
constructor(name:string,age:number,sound:string){
// 如果子类写了构造函数,在子类构造函数中必须对父函数进行调用
super(name,age) //调用父类构造函数
this.sound=sound
}
run(){
console.log('狗子在跑');
}
// 重写
bark(){
console.log('汪汪汪');
}
sayHello(){
// 在类的方法里super表示当前类的父类
super.sayHello()
}
}
let dog=new Dog('小狗',5,'汪汪')
dog.sayHello()
console.log(dog);
抽象类
/*
以abstract开头的类是抽象类
抽象类和其他类区别不大,只是不能用来创建对象
抽象类是专门用来继承的类
抽象类中可以添加抽象方法
*/
abstract class Animal{
name:string;
age:number;
constructor(name:string,age:number){
this.name=name
this.age=age
}
// 定义一个抽象方法
// 抽象方法使用abstract开头,没有方法体
// 抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写
abstract sayHello():void;
}
class Dog extends Animal{
sayHello(){
console.log('汪汪汪');
}
}
let dog=new Dog('小狗',5)
dog.sayHello()
console.log(dog);
接口
// 描述一个对象类型
type myType={
name:string,
age:number
}
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:'男'
}
/**
* 接口可以在定义类的时候去限制类的结构
* 接口中的所有属性都不能有实际的值
* 接口只定义对象的结构,而不考虑实际的值
* 在接口中所有的方法都是抽象方法
*/
interface myInter{
name:string;
sayHello():void;
}
/**
* 定义类时,可以使类去实现一个接口
* 实现接口就是使类满足接口要求
*/
class MyClass implements myInter{
name:string
constructor(name:string){
this.name=name
}
sayHello(): void {
console.log('hello');
}
}
属性的封装--修饰符
class Person{
// TS可以在属性前添加属性修饰符
/**
* public 修饰的属性可以在任意位置被访问(修改)默认值,子类也可以
* private 私有属性,私有属性只能在类内部进行访问(修改)
* - 通过在类中添加方法使得私有属性可以被外部访问
* - 子类不可以
* protected 受保护的属性,只能在当前类和当前类的子类中访问
*
*
*/
name:string;
age:number;
private _money:number;
constructor(name:string,age:number,money:number){
this.name=name;
this.age=age;
this._money=money
}
// TS中设置gtter方法的方式
get money(){
return this._money
}
set money(value:number){
this._money=value
}
// 定义方法获取money属性
// getMoney(){
// return this.money
// }
// 定义方法,用来设置money属性
// setMoney(value:number){
// this.money=value
// }
}
const per = new Person('张三',18,1000000000);
/**
* 现在属性是在对象中设置的,属性可以任意被修改
* 属性可以任意被修改将会导致对象中的数据变得非常不安全
*/
per.name='李四'
per.age=-18
class C{
// 可以将属性直接定义在构造函数中
constructor(public name:string){}
}
new C('李四')
泛型
/**
* 在定义函数或者是类时,如果遇到类型不明确就可以使用泛型
*/
function fn<T>(a:T):T{
return a;
}
// 可以直接调用具有泛型的函数
fn(10);//不指定泛型,TS可以自动对类型进行推断
fn<string>('hello');//指定泛型
// 泛型可以同时指定多个
function fn2<T,K>(a:T,b:K):T{
return a;
}
fn2<number,string>(123,'')
interface Inter{
length:number;
}
// T extends Inter 表示泛型T必须是Inter实现的类(子类)
function fn3<T extends Inter>(a:T):number{
return a.length
}
fn3('123')
class MyClass<T>{
name:T;
constructor(name:T){
this.name=name;
}
}
new MyClass<string>('孙氏')