共计 12122 个字符,预计需要花费 31 分钟才能阅读完成。
一、简介
TypeScript 是微软开发的一个开源的编程语言,通过在 JavaScript 的根底上增加动态类型定义构建而成。TypeScript 通过 TypeScript 编译器或 Babel 转译为 JavaScript 代码,可运行在任何浏览器,任何操作系统。
装置 ts
// 装置:npm install -g typescript | |
// 查看版本 | |
tsc -v |
注:编写 ts 文件,运行 ts 文件是先编译成 js 后在执行 js,想间接执行 ts,可装置 ts-node。
二、根底类型
js 根底类型分为两种:原始类型和对象类型,其中原始类型包含:数值、字符串、布尔值、null、undefined 以及 es6 中的 symbol、biignt。
ts 反对与 js 简直雷同的数据类型。
1、布尔值 / 字符串 / 数值
//var [变量名] : [类型] = 值; | |
let isDone: boolean = false; | |
const num: number = 1; | |
const name: string = "猪猪"; | |
// 字符串模板仍旧能用 | |
const str:string=`${name}` | |
// 申明变量的类型,但没有初始值,变量值会设置为 undefined://var [变量名] : [类型]; | |
var test: string; | |
// 申明变量并初始值,但不设置类型,该变量能够是任意类型://var [变量名] = 值; | |
var uname = "abc"; | |
// 申明变量没有设置类型和初始值,类型能够是任意类型,默认初始值为 undefined://var [变量名]; | |
var cord; |
(1)num 申明变量的类型 number 之后,前面赋值时,得跟数值,否则则会报错,因为变了 num 的类型是数值。
(2)如果变量的申明和赋值是同时进行的,ts 能够主动对变量进行类型检测。
let str: string; | |
str = 'hello'; | |
str = 9; // 报错 |
2、null 和 undefined
// 这两个类型只有 本人 | |
const onlyNull: null = null; | |
const onlyUndefined: undefined = undefined; |
3、数组
// 数组泛型,Array< 元素类型 > | |
let list: Array<number> = [1, 2, 3]; | |
//string[] 字符串数组 | |
let list: string[]; | |
list = ['a', 'b', 'c']; | |
//number[] 数值数组 | |
let list: number[] = [1, 2, 3]; |
4、元组
元组 元组就是固定长度的数组
// 语法:[类型, 类型, 类型] | |
let list: [string, number]; | |
list = ['hello', 123]; | |
list = ['hello'];// 报错 | |
list = [123, 'hello']; // 程序不统一 | |
list = ['hello', 123, 11]; // 多余 |
5、枚举
枚举类型也的确属于对象类型
ts 只反对基于数字和字符串的枚举
对于基于数字的枚举类型反对键值对的反向映射 key<=>value
基于字符串的不能够反向映射?当然不能够, 就是纯 js 对象
// | |
// 枚举 | |
enum Gender{ | |
Male, | |
Female | |
} | |
let i: {name: string, gender: Gender.Male}; | |
i = { | |
name: '猴子', | |
gender: Gender.Male | |
} | |
console.log(i.gender === Gender.Male); //true |
字符串枚举
enum Language{ | |
java="J", | |
node="N", | |
php="P", | |
python="PY" | |
} | |
// 打印一下 | |
console.log(Language) | |
// 输入后果 | |
{java: 'J', node: 'N', php: 'P', python: 'PY'} | |
// 编译后的 js | |
var Language; | |
(function (Language) {Language["java"] = "J"; | |
Language["node"] = "N"; | |
Language["php"] = "P"; | |
Language["python"] = "PY"; | |
})(Language || (Language = {})); | |
// 打印一下 | |
console.log(Language); | |
数字枚举 - 默认增长
enum Language{ | |
html, | |
node, | |
js, | |
python | |
} | |
// 打印一下 | |
console.log(Language) | |
// 输入后果 | |
{ | |
'0': 'html', | |
'1': 'node', | |
'2': 'js', | |
'3': 'python', | |
html: 0, | |
node: 1, | |
js: 2, | |
python: 3 | |
} | |
// 编译后的 js | |
var Language; | |
(function (Language) {Language[Language["html"] = 0] = "html"; | |
Language[Language["node"] = 1] = "node"; | |
Language[Language["js"] = 2] = "js"; | |
Language[Language["python"] = 3] = "python"; | |
})(Language || (Language = {})); | |
// 打印一下 | |
console.log(Language); |
数字枚举 - 自定义增长
enum Language{ | |
html=6, | |
node, | |
js, | |
python | |
} | |
// 打印一下 | |
console.log(Language) | |
// 输入后果 | |
{ | |
'6': 'html', | |
'7': 'node', | |
'8': 'js', | |
'9': 'python', | |
html: 6, | |
node: 7, | |
js: 8, | |
python: 9 | |
} | |
// 编译后的 js | |
var Language; | |
(function (Language) {Language[Language["html"] = 6] = "html"; | |
Language[Language["node"] = 7] = "node"; | |
Language[Language["js"] = 8] = "js"; | |
Language[Language["python"] = 9] = "python"; | |
})(Language || (Language = {})); | |
// 打印一下 | |
console.log(Language); |
异构枚举
enum Person{ | |
age = 18, | |
gender = 'male' | |
} | |
// 打印一下 | |
console.log(Person) | |
// 输入后果 | |
{'18': 'age', age: 18, gender: 'male'} | |
// 编译后的 js | |
var Person; | |
(function (Person) {Person[Person["age"] = 18] = "age"; | |
Person["gender"] = "male"; | |
})(Person || (Person = {})); | |
// 打印一下 | |
console.log(Person); |
6、| 和 &
// | 或 示意能够是字符串或数值 | |
let str: string | number; | |
str = 1; | |
console.log(str.length)// 报错 | |
str = 'hello'; | |
console.log(str.length)// 失常运行 | |
str = false; // 报错 | |
//& 示意同时 | |
let str2: {name: string} & {age: number}; | |
str2 = {name: '嘿嘿'}; // 报错 | |
str2 = {name: '嘿嘿', age: 18}; |
7、type
// type | |
// 类型的别名 | |
type myType = string; | |
let k: 1 | 2 | 3 | 4; | |
let m: myType //m 类型是 string | |
type myType2 = 1 | 2 | 3 | 4; | |
k = 1; | |
k = 6;// 报错 |
8、function
//js 不思考参数的类型和个数的 | |
function sum(a, b) {return a + b;}; | |
// ts 隐式 any | |
function sum(a: any, b:any):any {return a + b;}; | |
function sum2(a:number, b:number): number {return a + b;}; | |
let s1 = sum('1', 2); // 12 | |
let s2 = sum(2, 2); // 4 | |
let s3 = sum2(1, 5); // 6 | |
console.log(s1, s2, s3); | |
9、任意值
任意值 (any/unknown) 用来示意容许赋值为任意类型
any
//any 示意任意类型的值,一个类型应用了 any 后相当于敞开了 ts 的类型检测 | |
// 在应用 ts 时 不倡议应用 any | |
let a: any | |
a = 1; | |
a = 'hello'; | |
a = false; | |
// 如果变量不申明类型,则 ts 解析器会主动判断变量的类型为 any(隐式 any)let b; | |
b = 1; | |
b = 'hello'; | |
b = true; | |
let s: string; | |
// b 的变量是 any,它能够赋值给任意变量 | |
s = b; |
unknown
//unknown 示意未知类型的值 | |
let c: unknown | |
c = 1; | |
c = 'hello'; | |
c = false; | |
let s: string; | |
c = 'world'; | |
// 把 c 赋值给 s,也就是把未知变量赋值给其余类型变量会报错 | |
s = c;// 报错 | |
//unknown 实际上就是一个类型平安的 any | |
//unknown 不能间接赋值给任意变量 | |
// 判断类型 | |
if (typeof c === 'string') {s = c;} | |
// 类型断言 用来通知解析器变量的理论类型 | |
s = c as string; | |
s = <string> c; |
10、void
const u:void=undefined; | |
const n:void=null; | |
const age:void=18;// 不能将 number 类型赋值给 void | |
//void 用来示意空 以函数为例 就示意没有返回值的函数 | |
function fn() {} | |
function fn2(): void {} |
11、never
//never 示意永远不会返回后果 | |
function fn(): never {throw new Error('谬误的'); | |
} | |
// 非凡状况下, 变量也能够应用 never 申明, 比方一个永远为空的数组。never 是任何类型的子类型, 也能够赋值给任何类型, 然而反过来不能够。(本身除外) | |
const emptyArr: never[] = [] |
12、object
//object 示意一个 js 对象 | |
let a: object; | |
a = {} | |
a = function() {} | |
//{}用来指定对象中能够蕴含哪些属性 | |
// 语法:{属性名:属性值} | |
// 属性名前面加上? 示意属性是可选的 | |
let b: {name: string, age?: number}; | |
b = {};// 报错 短少属性名 | |
b = {name: '阿三'}; | |
b = {name: '李四', age: 12}; | |
// [propName: string]: any 示意任意类型的属性 | |
let c: {name: string, [propName: string]: any}; | |
c = {name: '嘿嘿', age: 12, gender: '男'}; | |
// 设置函数构造的类型申明 | |
// 语法:(形参:类型, 形参:类型...) => 返回值 | |
let d: (a: number, b: number) => number; | |
d = function(n1, n2):number {return n1 + n2;} | |
//d = function(n1: string, n2:string): number { | |
// return 10; | |
// } | |
// 报错 |
13、symbol
symbol 应用依赖 es6 编译辅助库 ,tsconfig.json lib[“es6”]
const sym1: symbol = Symbol(); | |
const sym2: symbol = Symbol(); | |
console.log(sym1===sym2); //false | |
let sym3 = Symbol("key"); | |
let sym4 = Symbol("key"); | |
sym2 === sym3; // false, symbol 是惟一的 |
三、面向对象
1⃣️操作浏览器应用 window 对象
2⃣️操作网页应用 document 对象
3⃣️操作控制台应用 console 对象
万物皆对象
1、类(class)
简介:要创建对象,必须先定义类,所谓的类能够了解为对象的模型。举例说明:能够通过 Person 类来创立人类的对象,通过 Dog 类来创立狗的对象等等,不同的类用来创立不同的对象。
Person 类
// 应用 class 关键字定义一个类 | |
/** | |
* 对象中蕴含了两个局部:* 属性 | |
* 办法 | |
* | |
*/ | |
class Person { | |
// 定义实例属性 | |
name: string = '猴子'; | |
age: number = 18; | |
// 动态属性 | |
static num: number = 1; | |
// readonly | |
readonly gender: string = '男'; | |
static readonly say: string = 'hello'; | |
// 定义方法 | |
/** | |
* | |
* 通过 static 定义类办法 能够间接用类去调用 | |
*/ | |
syaHello() {console.log('hello, 大家好'); | |
} | |
} | |
const son = new Person(); | |
son.syaHello(); // hello, 大家好 | |
console.log(son); | |
console.log(son.age, son.name); | |
console.log(son.age, son.name, son.num); // 报错 没有 num 这个属性 | |
son.gender = '女'; // 报错 因为 readonly 是只读的属性 不可批改 | |
Person.say = '1212'; // 应用 static 结尾且只读的属性 不可批改 | |
Person.num; // 应用 static 结尾的属性是动态属性(类属性),能够间接通过类去调用 | |
// 打印后果 | |
Person {name: "猴子", age: 18} | |
18 "猴子" |
dog 类
class Dog{ | |
name: string; | |
age: number; | |
// constructor 构造函数 构造函数会在对象创立时调用 | |
constructor(name: string, age: number) { | |
// 在实例办法中 this 示意以后的实例 | |
// 能够通过 this 向新建的对象中增加属性 | |
this.name = name; | |
this.age = age; | |
} | |
brak() { | |
// 在办法中能够用 this 示意以后调用办法的对象 | |
//console.log('汪汪汪'); | |
console.log(this.name); | |
} | |
} | |
const dog1 = new Dog('小黑', 10); | |
const dog2 = new Dog('小白', 11); | |
console.log(dog1); // {name: "小黑", age: 10} | |
console.log(dog2); // {name: "小白", age: 11} | |
dog1.brak(); // 小黑 | |
2、继承
(function() { | |
// 定义 animal 类 | |
class Animal { | |
name: string; | |
age: number; | |
// constructor 构造函数 构造函数会在对象创立时调用 | |
constructor(name: string, age: number) { | |
// 在实例办法中 this 示意以后的实例 | |
// 能够通过 this 向新建的对象中增加属性 | |
this.name = name; | |
this.age = age; | |
} | |
sayHello() {console.log('动物在叫~'); | |
} | |
} | |
/** | |
* 此时 Animal 被称为为父类 Dog、Cat 被称为子类 | |
* 应用继承后 子类将会领有父类的所有办法和属性 | |
* 如果在子类中增加了和父类的雷同的办法 则子类办法会笼罩父类的办法 | |
*/ | |
// 定义狗的类 继承 Animal 类 | |
class Dog extends Animal {run() {console.log(`${this.name}在跑路~~~`); | |
} | |
sayHello() {console.log('汪汪汪'); | |
} | |
} | |
// 定义猫的类 继承 Animal 类 | |
class Cat extends Animal { } | |
const dog = new Dog('小黑', 3); | |
const cat = new Dog('咪咪', 2); | |
console.log(dog); // Dog {name: "小黑", age: 3} | |
dog.sayHello(); // 汪汪汪 | |
dog.run(); // 小黑在跑路~~~ | |
console.log(cat); //Dog {name: "咪咪", age: 2} | |
cat.sayHello(); // 动物在叫~ | |
cat.run(); // 报错})(); |
3、super
// 超类 | |
(function() { | |
// 定义 animal 类 | |
class Animal { | |
name: string; | |
constructor(name: string) {this.name = name;} | |
sayHello() {console.log('动物在叫~'); | |
} | |
} | |
class Dog extends Animal { | |
age: number; | |
constructor(name: string, age: number) { | |
// 如果在子类中写了构造函数 在子类函数中必须对父类的构造函数进行调用 | |
super(name); // 调用父类的构造函数 | |
this.age = age; | |
} | |
sayHello() { | |
// 在类的办法中 super 示意以后类的父类 | |
//super.sayHello(); | |
console.log('汪汪汪'); | |
} | |
} | |
const dog = new Dog('小黑', 2); | |
dog.sayHello(); // 汪汪汪 | |
console.log(dog); // Dog {name: "小黑", age: 2} | |
})(); |
4、抽象类
(function() { | |
// 定义 animal 类 | |
/** | |
* 以 abstract 结尾的类是抽象类 | |
* 抽象类与其余类区别不大 只是不能用来创建对象 | |
* 抽象类就是专门用来继承的类 | |
* | |
* 抽象类中能够增加形象办法 | |
*/ | |
abstract class Animal { | |
name: string; | |
constructor(name: string) {this.name = name;} | |
// 形象办法应用 abstract 结尾 没有办法体 | |
// 形象办法只能定义在抽象类中 子类必须对起形象办法重写 | |
abstract sayHello(): void;} | |
class Dog extends Animal {sayHello() { | |
// 在类的办法中 super 示意以后类的父类 | |
//super.sayHello(); | |
console.log('汪汪汪'); | |
} | |
} | |
class Cat extends Animal { } // 报错 没有实现 s 对 ayHello 重写 | |
const dog = new Dog('小黑'); | |
dog.sayHello(); | |
console.log(dog); | |
//const ani = new Animal(); // 报错 无奈创立实例})(); |
5、接口
(function() { | |
// 形容一个对象的类型(别名模式)type myType = { | |
name: string, | |
age: number | |
} | |
// type myType = {} // 报错 反复申明 | |
/** | |
* 接口用来定义一个类构造,用来定义一个类中应该蕴含哪些属性和办法 | |
* 接口也可用来当成类型申明去应用 | |
* | |
* 接口可反复申明 | |
*/ | |
interface myInterface { | |
name: string, | |
age: number | |
} | |
interface myInterface {gender: string} | |
const obj: myInterface = { | |
name: '哈哈哈', | |
age: 12, | |
gender: '男' | |
} | |
/** | |
* 接口能够在定义类的时候限度类的构造 | |
* 接口中的所有属性都不能有理论的值 | |
* 接口只定义类的构造 而不思考理论值 | |
*/ | |
interface myInter { | |
name: string; | |
sayHello(): void;} | |
/** | |
* 定义类时,能够使类去实现一个接口 | |
* 实现接口就是使类满足接口的要求 | |
* | |
*/ | |
class MyClass implements myInter { | |
name: string; | |
// 须要写构造函数 给 name 赋值 | |
constructor(name: string) {this.name = name;} | |
sayHello() {console.log('大家好'); | |
} | |
} | |
const m = new MyClass('嘻嘻'); | |
m.sayHello(); // 大家好 | |
console.log(m); // MyClass {name: "嘻嘻"} | |
})(); | |
// 编译后的 js | |
"use strict"; | |
(function () { | |
const obj = { | |
name: '哈哈哈', | |
age: 12, | |
gender: '男' | |
}; | |
/** | |
* 定义类时,能够使类去实现一个接口 | |
* 实现接口就是使类满足接口的要求 | |
* | |
*/ | |
class MyClass { | |
// 须要写构造函数 给 name 赋值 | |
constructor(name) {this.name = name;} | |
sayHello() {console.log('大家好'); | |
} | |
} | |
const m = new MyClass('嘻嘻'); | |
m.sayHello(); | |
console.log(m); | |
})(); |
6、属性的封装
(function() { | |
// 定义一个人的类 | |
class Person { | |
// ts 能够在属性前增加修饰符 | |
/** | |
* public 润饰的属性能够在任意地位拜访(批改)默认值 | |
* private 公有属性 只能在对象外部中拜访(批改)默认值 | |
* protected 受爱护的属性 只能在以后类和以后类的子类拜访 | |
* | |
*/ | |
private _name: string; | |
age: number; | |
constructor(name: string, age: number) { | |
this._name = name; | |
this.age = age; | |
} | |
// 定义方法 获取 name 属性 | |
// getName() { | |
// return this._name; | |
// } | |
// 定义方法 设置 name 属性 | |
// setName(value: string) { | |
// this._name = value; | |
// } | |
// ts 中设置 getter 办法的形式 | |
get name() {console.log('get name() 办法执行了 ---'); | |
return this._name; | |
} | |
set name(value: string) {this._name = value;} | |
} | |
const per = new Person('猴子', 18); | |
/** | |
* 当初属性是在对象中设置的 属性能够任意被批改 | |
* 属性被任意批改会导致对象中的数据变得十分不平安 | |
* | |
*/ | |
//per._age = 20; // 报错 不能拜访 | |
//per.name = '八戒'; | |
//console.log(per); // 输入:{name: "八戒", age: 20} | |
// per.setName('八戒'); | |
// console.log(per.getName()); // 输入:八戒 | |
console.log(per.name); // get name() 办法执行了 --- 猴子 | |
per.name = '八戒'; | |
console.log(per.name); // 八戒 | |
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 = 55; // 只能在类“A”及其子类中拜访 | |
class C { | |
// 能够间接将属性定义在构造函数中 | |
constructor(public name: string, public age: number) { | |
this.name = name; | |
this.age = age; | |
} | |
} | |
const c = new C('xxx', 123); | |
console.log(c); // {name: "xxx", age: 123} | |
})(); |
7、泛型
// function fn(a: number): number { | |
// return a; | |
// } | |
/** | |
* 在定义类或函数时 如果遇到类型不明确就能够应用泛型 | |
* | |
*/ | |
function fn<T>(a: T): T {return a;} | |
// 间接调用具备泛型的函数 | |
const result = fn(123); // 不指定泛型 ts 会主动对类型进行推断 | |
const result2 = fn<string>('hello'); // 指定泛型 | |
// 多个 | |
function fn2<T, K>(a: T, b: K): T {return a;} | |
const result3 = fn2<number, string>(123, 'hello'); | |
interface Inter {length: number} | |
function fn3<T extends Inter>(a: T): number {return a.length;} | |
fn3('122'); // 3 | |
//fn3(123); // 类型“number”的参数不能赋给类型“Inter”的参数 | |
fn3({length: 10}); // 10 | |
// 定义类也能够应用泛型 | |
class MyClass<T> { | |
name: string; | |
constructor(name: string) {this.name = name;} | |
} | |
const c = new MyClass<string>('哈哈哈'); | |
//const d = new MyClass<number>(123); // 类型“number”的参数不能赋给类型“string”的参数 |
四、我的项目配置
编译选项
1、运行 ts 文件
tsc test.ts | |
// 监听当个文件 实时编译 | |
tsc test.ts -w | |
// 监听全副 ts 文件 | |
tsc -w | |
// 编译所有 ts 文件 | |
tsc |
2、tsconfig.json
{ | |
// 编译器选项 | |
"compilerOptions": { | |
// module 应用类型:none,commonjs,amd,system,umd,es6,es2015... | |
"module": "es2015", | |
// target 默认 es3 | |
"target": "ES2015", | |
// 开启全副严格模式 | |
"strict": true, | |
// outDir 输入目录 | |
"outDir": "./dist" | |
//lib 用来指定应用的库 个别不必写 | |
//lib: [], | |
// outFile 将全局作用域中的代码合并成一个 用的不多 | |
"outFile": "./dist/app.js", | |
// 是否编译 js 默认 false | |
"allowJs": false, | |
// 是否查看 js 默认 false | |
"checkJs": false, | |
// 是否革除正文 默认 false | |
"removeComments": false, | |
// 不生成编译后的文件 | |
//"noEmit": false, | |
// 当有谬误时不生成编译文件 | |
"noEmitOnError": false, | |
// 设置严格模式 | |
"alwaysStrict": false, | |
// 不容许隐式 any | |
"noImplicitAny": false, | |
// 是否检测 null | |
"strictNullChecks": false | |
}, | |
// 只编译 src 目录下的 ts 文件 | |
"include": ["./src/**/*"], | |
// 不须要被编译的 ts 文件 | |
"exclude": ["./src/hello/**/*"] | |
} |
3、检测 null
const div = document.getElementById('.div'); | |
if (div !== null) {...} | |
div?.addEventListener('click', function() {console.log('aaaa'); | |
}); |
4、我的项目构造
五、应用 webpack 打包 ts 代码
1、装置依赖
// 我的项目初始化 | |
npm init -y | |
// 装置工具 | |
npm i -D webpack webpack-cli typescript ts-loader |
2、webpack.config.js 配置
const path = require('path'); | |
// webpack 中的所有配置信息都应该写到 module.export 中 | |
module.exports = { | |
// 入口文件 | |
entry: "./src/index.ts", | |
// 打包文件 | |
output: {path: path.resolve(__dirname, 'dist'), | |
filename: "bundle.js" | |
}, | |
// 打包应用的模块 | |
module: { | |
rules: [ | |
{ | |
test: /\.ts$/, | |
use: "ts-loader", | |
exclude: "/node_modules/" | |
} | |
] | |
} | |
}; |
3、tsconfig.js 配置
{ | |
"compilerOptions": { | |
"module": "ES2015", | |
"target": "ES2015", | |
"strict": true | |
} | |
} |
4、html-webpack-plugin 配置
装置:
npm i html-webpack-plugin -D
配置:
// 引入 html-webpack-plugin | |
const HtmlWebpackPlugin = require('html-webpack-plugin'); | |
// 配置 webpack 插件 | |
plugins: [ | |
new HtmlWebpackPlugin({template: "./src/index.html"}) | |
] |
5、热更新
装置:
npm i webpack-dev-server -D
配置:
"dev": "webpack serve --open'google chrome'"
运行:
npm run dev
6、clean-webpack-plugin 配置
装置:
npm i clean-webpack-plugin -D
配置:
// 引入 | |
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); | |
// 应用 | |
new CleanWebpackPlugin() | |
7、模块引入
在 a.ts 中裸露一个变量,而后在 index.ts 去引入,然而在打包过程中会报错,引入 webpack 不能辨认引入的模块,因而须要去设置,须要在 webpack.config.js 中增加 resolve,用来设置模块引入文件的扩展名。
配置:
resolve: { | |
extensions: [ | |
'.ts', | |
'.js' | |
] | |
} |
a.ts
export const h: string = '123';
index.ts
import {h} from './a'; | |
console.log(h); |
8、babel
npm i @babel/core @babel/preset-env babel-loader core-js -D
六、vue3 + typesctipt
七、学习材料
学习链接:编译选项
在线运行:typescript Playground