前言
1、TypeScript 起源于使用JavaScript开发的大型项目 。由于JavaScript语言本身的局限性,难以胜任和维护大型项目开发。因此微软开发了TypeScript ,使得其能够胜任开发大型项目。
2、TypeScript 是JavaScript添加了可选的静态类型和基于类的面向对象编程。
3、TypeScript 是一门弱类型的语言。
4、TypeScript扩展了JavaScript的语法,所以任何现有的JavaScript程序可以运行在TypeScript环境中。
5、TypeScript 可以编译为 JavaScript,然后运行在浏览器、Node.js 等任何能运行 JavaScript 的环境中。
6、TypeScript 可以和 JavaScript 共存,这意味着 JavaScript 项目能够渐进式的迁移到 TypeScript。
7、TypeScript 与标准同步发展,符合最新的 ECMAScript 标准(stage 3)
8、TypeScript 仅仅是被编译为标准的 JavaScript。支持运行于任何浏览器和平台上的任何网页。
9、TypeScript 的编译步骤可以检查出很多错误。
1、安装依赖
// 安装typescript工具
cnpm install typescript -g
// 其他依赖包
//eslint所需
@typescript-eslint/parser // 解析器
@typescript-eslint/eslint-plugin // 插件
其他常用命令
tsc xx.ts // 把xx文件转化成js文件
tsc xx.ts -w // 监听文件变化,自动转成js文件
// 如果想让所有ts文件都自动转换,首先需要根目录需要有tsconfig.json配置文件
tsc -init // 创建tsconfig.json
tsc // 把所有ts文件转成js文件
tsc -w // 自动把修改的ts文件转换成js文件
2、类型声明
包含boolean、string、number、字面量、any、unknown、void、never、 object、array、元组tuple、枚举enum
其中包含|用法、断言用法
/**
* 字面量
* 写法一:变量:值|值
*/
// 字面量--值
let a: "man" | "women"; // a只能为"man"或"women"
a = "man";
a = "women";
a = 34324; // 报错
/**
* 字面量
* 写法二:变量:类型|类型
*/
let b: boolean | string; // b只能为boolean或string类型
b = true;
b = "woshi";
b = 1242; // 报错
console.info(b);
/**
* any
* 写法:变量:any
* any--指c可以为任何值,any变量也可以赋值给任何类型变量, 不推荐用
*/
let c: any;
c = "123";
let c1: number = c; // 可以让c1变量number的约束失效
/**
* unknown
* 写法:变量:unknown
* 安全的any,指c可以为任何值,unknown变量不可以赋值给unknown类型之外的变量(可以用断言解决)
*/
let d: unknown;
d = 123;
let d1: number = d; // 报错
let d2: number = d as number; // 对于编译器来说d是unknown类型的,unknown不能赋值给number类型变量,断言就是告诉编译器d为number类型
let d3: string = d as number; // 报错,number类型不能赋值string变量
let d4: unknown = d;
/** void
* 1、表示函数无返回值/return /return undefined
* 2、作为类型声明一个变量,但只能够赋值为null和undefined
*/
let f1 = function(): void {
//函数没写return
// 只写了 return, 没有具体的返回值
// return 的是 undefined
}
let dd: void = null;
/** never表示函数完全无返回
* 1、一个从来不会有返回值的函数,即死循环,如while(true)
* 2、一个总是会抛出错误的函数
*/
// 1
let fn = () => {
// 手动通过 throw 抛出一个异常(错误)
throw new Error('err...')
}
let n = fn() // n => never
// 2
let fn = () => {
while (true) {}
}
let n = fn() // n => never
/**
* object--对象
* 写法:变量:{属性名: 类型}
*/
let e: object;
let e1: { name: string }; // 表示e1这个对象里有且只有name属性,类型必须是string
let e2: { name?: string }; // name?表示name属性可有可无
let e3: { name: string; [xx: string]: unknown }; // id是必要的,其他的key:value任意数量,满足string:unknown类型即可
e3 = { name: "w", sex: 1, haha: 6 };
/**
* object--方法
* 写法:变量:(形参:类型)=> 返回值
*/
let f: (x: number, y: string) => string; // e4是一个方法,参数分别为number和string,返回值是string
f = function (start: number, end: string) {
return "123";
};
/**
* array
* 写法一:Array<类型>
* 写法二:类型[]
*/
let g: Array<string>; // 数组里面只能有string
let g1: string[]; // 同上
/**
* 元组tuple
* 表示定长的数组,效率高
* 写法:变量:[第一项类型, 第二项类型, ...]
* 必须严格按照每一项的类型写值,且长度不可改变
*/
let yuanzu: [string, number];
yuanzu = ["ss", 123];
yuanzu = ["ss", 123, 34]; // 报错
yuanzu = ["ss", ""]; // 报错
/**
* 枚举enum
* 表示一类数据的集合,类似于字典值
*/
enum payWay {
Alipay = 1,
Wxpay = 2,
}
let user = { name: "王", payWay: 1 }; // 假设一个用户的信息,判断他的支付方式
if (user.payWay == payWay.Alipay) {
console.info("支付宝支付");
}
3、类型的别名/自定义类型
/**
* 类型的别名/自定义类型
* 写法:type 别名 = 值
*/
type week = "星期一" | "星期二" | "星期四"; // 起别名或自定义类型
let type: week; // 表示type变量满足week类型,只能从三者里取值
let type2: week;
type = "星期"; // 报错 不在三者里
4、tsconfig.json配置
babel可以把js转成兼容性代码,兼容ie等
@babel/core ts转js实现兼容性的核心代码
@babel/preset-env 拿到package.json浏览器兼容版本的配置,使用不同版本的代码
babel-loader 把babel和webpack结合
core-js 模拟js的运行环境,让老版本浏览器能够执行新浏览器技术
.babelrc 可以单独抽离的babel配置文件
use[
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env"
]
]
}
}
]
4、class、接口implements和抽象abstract 类
- 接口implements
- 接口可以限制类的结构
- 接口中所有的属性都没有实际的值
- 接口中所有的方法都是抽象方法,不能有具体的实现
- 约束必须要有某属性和某方法才能用我这个类的方法
/**
* 接口可以限制类的结构
* 接口中所有的属性都没有实际的值
* 接口中所有的方法都是抽象方法,不能有具体的实现
* 约束必须要有某属性和某方法才能用我这个类的方法
*/
interface Test {
name: string;
sayHello(): void;
}
// 如果不声明name和sayHello方法会报错
class MyTest implements Test {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
// 你猜
}
}
- 抽象abstract 类
- 修饰class,代表此类不能实例化,只能被继承
- 修饰方法,代表他的子类必须要实现此方法
下面复习下class的学习,里面包含抽象类的例子。
- ”对象“是指用代码抽象地表示一个真实的物体,物体的行为是”对象“的方法,物体的描述关键词是”对象“的属性。
/**
* 类
* abstract 指抽象类,Person本身不能实例化,他的子类可以
*/
abstract class Person {
type: string;
// 构造函数可以在对象创建时调用
constructor(type: string) {
// 在实例方法中,this就表示当前实例
// 可以通过this向新建对象添加属性
this.type = type;
}
name = "米"; // name为实例属性
age = 12;
static staticAge = 123; // staticAge是指直接通过类Person访问的属性
readonly readonlyAge = 343; // readonlyAge指只读不能修改
sayHello() {
// 方法的写法
}
// 抽象方法:指子类必须要重写此方法
abstract sayHello1(): void;
}
class Student extends Person {
startStudy() {
console.info(this.type + "开始学习");
}
// 有abstract约束必须重写父类方法
sayHello() {
console.info("");
// 直接用super.sayHello()表示调用父类sayHello
}
sayHello1() {
// 有abstract约束必须重写父类方法
}
}
class Teacher extends Person {
// 自定义Teacher里的属性
sex: string;
// 子类构造函数要传父类构造函数的参数
constructor(type: string, sex: string) {
// super里只用写父类参数
super(type);
this.sex = sex;
}
startTeach() {
console.info(this.type + "开始教书" + this.sex);
}
sayHello1() {
// 必须重写父类方法
}
}
let student = new Student("学生");
let teacher = new Teacher("教师", "女");
student.startStudy();
teacher.startTeach();
5、public private protected 修饰符
- public
在类中、子类中,和通过实例都可以访问和修改 - private
只有在类中才能访问 - protected
在类中和子类中访问,通过实例不可以访问
private和protected如果要通过实例改值,可以通过方法
class MyTest{
constructor(public name: string, private _age: number) {
this.name = name;
}
get age() {
return this._age;
}
set age(value) {
if (value > 0) {
this._age = value;
}
}
}
let myTest = new MyTest("xiaomi", 12);
myTest.age = -1; // 改不成功,因为赋值做了约束
console.info(myTest.name, myTest.age);
console.info(myTest.name, myTest._age); // 报错,因为_age时private,不能在通过实例访问