耐心看完,上手写读保证没有问题。
往下滑还有关于 tsconfig webpack 的配置方法,耐心看完,受益匪浅。
码云库:https://gitee.com/pengpeng_fang/type-script
第一步先用 cmd 安装 typescript
npm i typescript
基本语法
//声明一个变量 同时指定它的类型只能为 number string
let a: string;
a = 'hello';
// 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测(声明)
let c = false;
// a b参数各设置为数字 括号后边写number代表着返回值也必须是number类型
function sum(a:number,b:number):number{
return a + b
}
TS类型
类型 | 例子 | 描述 |
---|---|---|
number | 1,-33,2.5 | 任意数字 |
string | ‘hi’,“hi”,hi | 任意字符串 |
boolean | true,false | 布尔值true或false |
字面量 | 其本身 | 限制变量的值就是该字面量的值 |
any | * | 任意类型 |
unknown | * | 类型安全的any |
void | 空值 (undefined) | 没有值 (或undefined) |
never | 没有值 | 不能是任何值 |
object | {name:孙悟空} | 任意的]S对象 |
array | [1,2,3] | 任意]S数组 |
tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
enum | enum{A, B} | 枚举,TS中新增类型 |
// 可以直接使用字面量进行类型声明
let d:10;
// d = 11; 但是不能从修改了
// | 可以使用 | 来连接多个类型(联合类型) 可以认为成 “或”
let e: boolean | string;
e = true;
e = "hello";
// any 表示任意值,一个变量设置类型为any后相当于对该变量关闭了TS的类型检测。
// 所以在使用TS时,不建议使用类型
// let f: any;
// 声明变量如果不指定类型,则TS解析器会自动判断变量的类型为any(隐式的any)
let f;
f = 10;
f = 'hello';
f = true;
// unknown 表示未知类型的值 实际上就是一个类型安全的any
let g: unknown;
g = 10;
g = 'hello';
g = true;
// a = f; 不报错 因为 any 类型可以赋值给任意定义好的类型
// a = g; 报错 unknown 不能直接复制给其他变量
// 类型断言 as 用来告诉TS解析器
/*
* 变量 as 类型
* <类型>变量
*/
a = g as string;
a = <string>g;
// void 用来表示空,以函数为例,就表示没有返回的函数
function fn():void{
}
// never 表示永远不会返回结果
function fn1(): never{
throw new Error('never')
}
// object表示一个js对象
// let h: object;
// h = {};
// h = function(){}
// 推荐使用 {} 用来指定对象中可以包含那些属性
// 语法:{属性名:属性值}
// let h: {name:string};
// h = {name:'熏悟空'}
// 问:如果对象里面有时候有别的参数怎么办?
// 方法一:在属性名后边加上? 表示属性可选 写不写都不报错
// let h: {name:string,age?:number};
// h = {name:'猪八戒'}
// 方法二:[propName:string]:any; 表示任意类型的属性
// let h: {name:string,[propName:string]:any;};
// h = {name:'沙悟净',}
/**
* 设置函数结构的类型声明:
* 语法:(形参:类型,形参:类型,)
* */
let h: (a:number,b:number)=>number;
h = function(n1,n2){
return n1+n2
}
// Array 表示一个js数组
/**
* 语法:
* 类型[]
* Array<类型>
*/
// let i:string[];
let i:Array<string>;
// 元组 就是固定长度的数组
let j: [string,string];
j = ['he','ll']
// enum 枚举
enum Gender{
Male,
Female
}
let k:{name:string,gender:Gender}
k = {
name:'熏悟空',
gender:Gender.Male
}
// & 表示同时
let l:{name:string}&{age:number}
l = {name:'熏悟空',age:10};
// 类型别名
type myType = 1 | 2 | 3;
let m: myType;
let n: myType;
Class 类
// class 的简介
// 使用class关键字来定义一个类
/**
* 对象中主要包含了两个部分:
* 属性
* 方法
* */
class one{
/**
* 直接定义的属性是实例属性,需要通过对象的实例去访问
* let o = new one();
* console.log(o.name)
* 使用static开头的属性是静态属性(类属性),可以直接通过类去访问
* console.log(one.age)
* 使用readonly开头的属性是只读属性,不能在修改了
*
* */
// 定义实例属性
readonly name:string = '老孙';
// 在属性前使用static关键字可以定义类属性(静态属性)
static readonly age:number = 15;
sex:string = '男';
// 定义方法
/**
* 方法名前也可以添加 static , 跟上边属性一样
* */
sayHello(){
console.log('第一 class');
}
}
let o = new one();
console.log(o)
o.sex = '女';
console.log(o);
// o.sayHello();
// public 后边有解释
// 语法糖写法
// class c{
// constructor(public name:string){
// this.name = name
// }
// }
// 构造函数和this指向问题
class two{
name:string;
age:number;
// constructor 被称为构造函数
// 构造函数会在对象创建时调用
constructor(name:string,age:number){
// 在实例方法中,this就表示当前的实例
// 在构造函数中当前对象就是当前新建的那个对象
// 可以通过this新建的对象中添加属性
this.name = name;
this.age = age;
}
bark(){
// 在方法中可以通过this来表示当前调用方法的对象
console.log(this)
}
}
let p = new two('小黑',7);
console.log(p)
// 继承
class five{
name:string;
age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
say(){
console.log('five:')
}
}
// 使 three four 继承 five
/**
* 此时,five 被称为父类,three four 被称为子类
* 使用继承后,子类将会拥有父类所有的方法和属性
* 通过继承可以将多个类中共有的代码写在一个父类中
* 这样只需要写一次即可让所有的子类都同时拥有父类中的属性和方法
* 如果希望在子类中添加一些父类中没有的属性或方法直接加就行
* 如果在子类中添加了和父类中相同的方法,则子类方法会覆盖父类的方法
* 子类覆盖掉父类方法的形式,成为方法重写
* */
class three extends five{
threeFuntion(){
console.log(`这是在three${this.name}`)
}
say() {
console.log('three')
}
}
class four extends five{
fourFuntion(){
console.log(`这是在four${this.name}`)
}
say() {
console.log('four')
}
}
let q = new three('小白',3);
let r = new four('小红',5);
q.say();
console.log(q);
r.say();
console.log(r);
// super 关键字
class six{
name:string;
constructor(name:string){
this.name = name;
}
say(){
console.log('six');
}
}
class seven extends six{
age:number;
constructor(name:string,age:number){
// 如果在子类中写了构造函数,在子类构造函数中必须对父类构造函数进行调用
// 因为在 six 里面又有了构造函数,seven在写构造函数的话就必须要用super()
// super() 就是调用父类的一个关键字
super(name);
this.age = age;
}
say(){
// 在类方法中 super就表示当前类的父类
// super.say();
// 直接这样写相当于直接重置了父类的方法
console.log('seven');
}
}
let s = new seven('小紫',9);
console.log(s)
// 抽象类
/**
* 以 abstract 开头的类时抽象类
* 抽象类中可以添加抽象方法
* 抽象类和其他类区别不大,只是不能直接 new 创建 只能靠继承
* 抽象类就是专门用来被继承的类
* */
abstract class eight{
name:string;
constructor(name:string){
this.name = name;
}
/**
* 定义一个抽象方法使用 abstract 开头
* 没有方法体 只能定义在抽象类中 子类必须对抽象方法进行重写
* */
abstract say():void;
}
class nine extends eight{
say(){
console.log(`nine${this.name}`);
}
}
let t = new nine('老六');
t.say();
// 接口
/**
* 接口就是用来定义一个类结构
* 用来定义一个类中应该包含那些属性和方法
* 同时接口也可以当成类型声明去使用
*
* */
// 类型 不可以重复声明的
type myTypes = {
name:string,
age:number,
}
// 接口 可以重复声明的
interface myInter{
name:string,
age:number,
}
interface myInter{
gender:string,
id:number,
}
const u:myInter = {
name:'老铁',
age:2,
gender:'男',
id:123
}
/**
* 接口可以在定义类的时候去限制类的结构
* 接口中的所有属性都不能又实际的值
* 接口只定义对象的结构,而不考虑实际值
* 在接口中所有的方法都是抽象方法
* */
interface myInterface {
name:string
say():void;
}
/**
* 定义类时,可以使用类去实现一个接口.
* 实现接口就是使类满足接口的要求
* */
class ten implements myInterface{
name: string;
constructor(name:string){
this.name = name;
}
say(): void {
throw new Error("Method not implemented.");
}
}
/**
* 抽象类 使用的是 extends 可以有抽象方法也可以有普通方法
* 接口 使用的是 implements 都是抽象方法
*/
// 属性封装
class eleven{
/**
* public 默认值 修饰的属性可以在任意位置访问(修改)包括继承之后的子类里
* private 私有属性 只能在类内部进行访问(修改)
* - 通过在类中添加方法使得私有属性可以被外部访问
* protected 受包含的属性,只能在当前类和当前类子类访问(修改)
*/
private _name: string;
private _age: number;
constructor(name:string,age:number){
this._name = name;
this._age = age;
}
/**
* getter 用来读取属性
* setter 用来设置属性
* - 它们被称为属性的存取器
*/
get name(){
console.log('get name()执行了!!')
return this._name;
}
set name(value:string){
this._name = value;
}
get age(){
console.log('get age()执行了!!')
return this._age;
}
set age(value:number){
if(value >=0){
this._age = value;
}
}
}
let v = new eleven('小六',20);
v.name = '大六';
v.age = -18;
console.log(v)
// 泛型
/**
* 在定义函数或是类时,如果遇到类型不明确就可以使用泛型
*/
function twelve<T>(a:T):T{
return a;
}
// 可以直接调用具有泛型的函数
let result = twelve(10); //不指定泛型,TS可以自动对类型进行推断
let result2 = twelve<string>('hello'); //指定泛型
function thirteen<T,K>(a:T,b:K):T|K{
if(Math.random() > 0.5){
return a
}else{
return b
}
}
console.log(thirteen(123,'hello'))
// 没看懂
interface Inter{
length: number;
}
function fourteen<T extends Inter>(a:T):number{
return a.length;
}
fourteen('1234')
配置 tsconfig
{
// tsconfig.json是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译
/*
* "include" 用来指定那些ts文件需要编译
* 路径: ** 表示任意目录
* * 表示任意文件
*/
// "include": ["./*"],
/*
* "exclude" 不需要被编译的文件目录
* 默认值:["node_modules","bower_components","jspm_packages"]
*/
// "exclude": [],
/*
* "extends" 有多个配置文件 继承的配置文件
* 默认值:"extends": "./config/base",
*/
// "extends": "",
/*
* "files" 指定被编译的文件列表 只有需要编译的文件少时才会用到
* 默认值:"files":["one.ts","two.ts","three.ts"],
*/
// "files":[]
/*
* "compilerOptions" 编译器的选择
* 默认值:"compilerOptions":{},
*/
"compilerOptions":{
// "target" 用来指定ts被编译为的ES的版本
// 参数 :"es5" "es6" "es7" "es2015" "es2016" "es2017" "esnext" ...
// 不确定有什么 那就随便 输入 控制台报错里面会给你提示
"target":"es6",
// "module" 指定要使用的模块化的规范
// 参数 :"none" "commonjs" "amd" "system" "umd" "es6" "es2015" "es2020" "esnext"
"module": "es6",
// "lib" 指定项目中要使用的库
// "lib":[],
// "outDir" 指定编译后的文件所在的目录
// "outDir": "./dist",
// "outFile" 将代码合并为一个文件 设置后,所有的全局作用域中的代码会合并到同一个文件中
// "outFile": "./app.js",
// "allowJS" 是否对js文件进行编译 默认false
"allowJs": false,
// "checkJs" 是否检查js代码是否符合语法规范 默认是false
"checkJs": false,
// "removeComments" 是否移除注释 默认false
"removeComments": false,
// "noEmit" 不生成编译后的文件
"noEmit": false,
// "noEmitOnError" 当有错误时不生成编译后的文件
"noEmitOnError": true,
// 所有严格检查的总开关
"strict": false,
// "alwaysStrict" 设置编译后的文件是否使用严格模式
"alwaysStrict": false,
// "noImplicitAny" 不允许隐式的any类型
"noImplicitAny": false,
// "noImplicitThis" 不允许类型不明确类型的this
"noImplicitThis": false,
// 严格的检查空值
"strictNullChecks": false,
}
}
配置webpack打包TS代码
// 对项目进行初始化操作
// npm init -y
// npm i -D webpack webpack-cli typescript ts-loader html-webpack-plugin webpack-dev-server clean-webpack-plugin @babel/core @babel/preset-env babel-loader core-js
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// webpack 中的所有配置信息都应该写在module.exports
module.exports = {
// development 发展 production 生产 none 禁用任何默认行为
mode:'production',
// 指定入口文件
// 单个文件
// entry:"./typeScript/TS.ts",
// 多个文件
// 例一:
// entry:["./typeScript/TS.ts", "./typeScript/class.ts"],
// 例二:
entry:{
TSA: "./typeScript/TS.ts",
TSB: "./typeScript/class.ts"
},
// 指定打包文件所在的目录
output:{
// 指定打包文件的目录
path:path.resolve(__dirname,'dist'),
// 打包后的文件
// ts 多个或单个 打包(合并)成一个 js
// filename:"bundle.js",
// 多个ts代码 各自打包各自成 js
filename:"[name].js",
// 告诉webpack不使用箭头函数
environment:{
arrowFunction:false,
}
},
// 指定webpack打包时要使用模块
module:{
// 指定要加载的规则
rules:[
{
// test指定的是规则生效的文件
test:/\.ts$/,
// 要使用的loader
use:[
// 配置 加载器
{
// 指定 加载器
loader: "babel-loader",
// 设置babel
options:{
// 设置预定义的环境
presets:[
[
// 指定环境插件
"@babel/preset-env",
// 配置信息
{
// 适配谷歌浏览器 88 是多少版本
targets:{
"chrome":"88"
},
"corejs":"3",
// corejs的方式
"useBuiltIns":"usage",
}
]
]
}
},
'ts-loader'
],
// 要排除的文件
exclude: /node-modules/
}
]
},
// 插件
plugins:[
new CleanWebpackPlugin(),
new HTMLWebpackPlugin({
// title:"自定义title",
template:'./index.html'
}),
],
// 引入模块
resolve:{
// 扩展名 凡是 ts js 结尾的文件都可以作为模块使用
extensions:['.ts','.js']
}
}