什么是 TS
- 以 JavaScript为基础构建的语言,一个 JavaScript 超集,
- TypeScript 是完全支持 JavaScript 的,并扩展了 JavaScript 添加了类型
- TS 不能直接被 JS 解析器直接执行,需要编译成 JS 在浏览器里执行
面向对象*
- 在程序中所有的对象都分成了两个部分数据和功能,以人为例,人的身高体重年龄等都为数据,能睡觉能吃饭能喝水都为人具有的功能。数据在对象中成为属性,功能在对象中称为方法,所以简而言之,一切皆对象
基本类型
- 类型声明
1.通过类型声明可以指定变量、函数的实参和形参的类型
2.指定类型后在为变量赋值时,TS 会自动识别值是否符合预设定类型,不符合则报错
3.如果变量的类型声明和赋值同时进行,可以省略变量类型声明, 默认为值的类型 - 语法
// let 变量名:类型 = 值;
let a:number = 1;
// a,b参数类型为number,并且函数返回值为 number
function fun(a:number,b:number):number {
return a+b;
};
- 类型
1.number
2.string
3.boolean
4.array
// 数组中每项的类型的限定
// 语法let a = string[]; 或者 let a = Array<string>
let a = string[];
let a = Array<number>;
a = [1,2,3,4];
5.object
// {}用来指定对象中包含哪些属性
// 语法{属性名:类型}
let a : object;
a = {};
a = function () {};
// 并且再次赋值需要属性相同,如果在属性后加?,表示该属性可选
a = {name:string,age?:number};
a = {name: '张三',age:12}
// 表示 a 对象必须有 name 属性,[propName:string]表示可选添加任意字符串类型的属性名,:any表示任意类型的属性值
a = {name:string,[propName:string]:any}
// 设置函数的类型声明
// 语法let a = (形参:类型,形参:类型...)=> 返回值
let a = (b:number,c:number) => number
a = (num1,num2) {
return num1 + num2
};
6.字面量 (限制变量的值就是字面量的值)
// 此后 a 的值只能是10或者12,赋值其他值报错
let a : 10 | 12;
7.any (任意类型)
// 类型为 any 后可以任意赋值,相当于关闭了类型检测,不推荐使用
// 声明变量后不指定类型,默认为隐式 any
let a : any;
a = 10;
a = 'hello';
a = false;
8.unknown (未知类型的值,类型安全的 any)
// any 和 unknown 的区别在与 any 给其他类型赋值时其他的类型也会变成 any,unknown 不会
let a : unknown;
a = 10;
a = 'hello';
a = false;
let b:number;
b = a; // 赋值会报错 unknown 类型不能赋值给 number
9.void (没有值或 undefined)
// void类型一般用于函数,表示函数返回空值或者 undefined
function fn():void {
return undefine; | return;
}
10.never (不能是任何值)
// never类型一般用于函数,表示函数永远不会返回值
function fn():never {
}
11.tuple (元组,TS 新增类型,固定长度数组)
// 限制数组长度和每项的类型,不能多也不能少
// 语法 [类型,类型,...]
let a = [string,number]
a = ['张三',18]
12.enum (TS 新增类型,枚举)
enum Gender {
male,
female
}
let i = {name:string,gender:Gender};
i = {
name: '孙悟空',
gender:Gender.male
}
- 类型断言
可以告诉解析器变量的实际类型
// 变量 as 类型
// <类型>变量
let a : number;
let s :12
s = a as number; // 告诉解析器 s 的值确定为 number
s = <number>a; // 另一种写法
- 类型别名
可以定义一个类型,重读使用
type Mytype = string;
let a:Mytype;
let b:Mytype;
a = '张三';
b = '李四';
编译选项
- tsconfig.json TS配置文件
{
// 指定哪些文件需要被编译
"include": ["./ts/src/**/*"],
// 指定哪些文件不能被编译,有默认值 node_modules,bower_components,jspm_packages
"exclude": ["./ts/src/app.ts"],
// 继承其他的配置文件
// "extends": ["../ts/ts"]
"compilerOptions": {
// target 指定 TS 编译后的 JS 版本
// 'es3', 'es5', 'es6', 'es2015', 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'es2021', 'es2022', 'esnext'
"target": "ES2015",
// module 指定要使用的模块化规范
// 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node16', 'nodenext'
"module": "System",
// lib 指定项目中使用的库,一般不需要修改
// "lib": []
// outDir 指定编译后的文件的路径
"outDir": "./ts/list",
// outFile 将编译后的代码合并到一个 js 文件中
"outFile": "./ts/list/app.js",
// checkJs是否编译 JS 文件,默认是 false
"allowJs": false,
// checkJs是否检查 JS 代码是否符合 TS 规范,默认是 false
"checkJs": false,
// removeComments是否取消注释
"removeComments": false,
// 所有严格检查的总开关
"strict": true,
// noEmit是否生成编译后的文件
"noEmit": false,
// noEmitOnError报错后不会编译
"noEmitOnError": false,
// alwaysStrict 是否使用 js 严格模式
"alwaysStrict": true,
// 检查是否存在隐式 any 类型
"noImplicitAny": true,
// 检查是否存在不明确类型的 this
"noImplicitThis": true,
// 检查是否存在空值
"strictNullChecks": true,
}
}
类(class)
- 直接定义的属性是实例属性,需要通过对象实例来获取
- 用 static 定义的属性是静态属性(类属性),可以直接通过类获取,方法同样
- readonly只读属性,不能修改
- constructor构造函数,在每次实例化类时调用
class person {
// 实例属性
name: string = '张三';
// 静态属性
static age: number = 18;
// readonly只读属性
readonly height: number = 100
// constructor 构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 定义方法
seyHello() {
console.log('hello',this.name);
}
}
let obj = new person('张三',18,);
// 实例属性调用
console.log(obj.name);
// 静态属性调用
console.log(person.age);
// 实例方法调用
console.log(obj.seyHello());
类继承
- dog 类继承 Animal类,Animal为父类,dog 为子类
- 使用继承后子类拥有所有父类的属性和方法
- 子类中可以直接添加父类中没有的属性和方法
- 如果在子类中添加了和父类相同的方法,则子类的方法会覆盖父类的方法
- 子类中super就相当于父类实例
- 如果在子类中调用 constructor ,那么就相当与覆盖了父类的 constructor 调用,所以必须在子类调用 constructor 添加 super();手动调用父类的constructor
// 父类
class Animal {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
bark() {
console.log('bark',this.name);
}
}
// 子类
class dog extends Animal {
age: number;
constructor(name: string, age: number) {
// 调用 super()方法,代替父类的构造函数调用
super(name,18)
this.age = age;
}
// 覆盖父类中 bark 方法
bark() {
// 通过 super 调用父类的方法
super.bark();
console.log('bark覆盖',this.name);
}
}
const dogObj = new dog('小明', 12);
dogObj.bark();
接口
- interface 接口用来定义类中包含的属性和方法,也可以当作 type 类型声明去使用
- 接口只定义类的结构不考虑实际值,接口中的所有属性不能有实际值,所有的方法都是抽象方法
- 通过implements实现接口,就是按照接口的要求创建类
interface myInterface {
name: string;
sayHello():void;
}
// implements 实现接口
class an implements myInterface {
name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
}
}
属性封装修改(访问) get&set
- private 修饰后的属性只能在内部访问,需要暴露 geter 和 seter 方法供外部访问修改
- 这样做的好处是,数据安全性,不能被外部随意访问修改,暴露了修改和访问的方法才能
- public默认修饰符,可以在任意位置访问修改(包括子类), private 只能在类内部访问修改,protected 受保护的属性,只能在父类和子类中访问修改
// private 修饰后的属性只能在内部访问,需要暴露 geter 和 seter 方法供外部访问修改
// 这样做的好处是,数据安全性,不能被外部随意访问修改,暴露了修改和访问的方法才能
//
// 属性修饰符
class A {
// public默认修饰符,可以在任意位置访问修改
public _name: string;
// private 只能在类内部访问修改
private _age: number;
// protected 只能在父类和子类中访问修改
protected _sex: string;
constructor(name: string, age: number,sex: string) {
this._sex = sex;
this._name = name;
this._age = age;
}
// 访问属性 get
get age() {
return this._age;
}
// 修改属性 set
set age(age: number) {
this._age = age;
}
}
const myObj = new A('张三', 12,'男');
// 通过 set 方法修改属性 age
myObj.age = 10;
// 访问修改后的 age
console.log(myObj.age);
class B extends A{
fn() {
// 访问父类中的 protected 修饰属性
console.log('sex',this._sex);
}
}
const Bfn = new B('张三', 12, '女');
Bfn.fn();
属性简写
- 可以直接将属性定义在构造函数中,加 public 修饰符
class D {
constructor(public name: string,public age: number,public sex: string) {
}
}
const d = new D('张三', 12, '男');
console.log(d)
泛型
- 如果在定义类或函数时,如果类型不明确就可以用泛型
// 定义泛型 T,K
class myClass<T,K> {
name:T;
constructor(name:T) {
this.name = name;
}
}
const J = new myClass(10); // 不指定泛型,TS 自动判断类型
const H = new myClass<string,number>('张三'); // 指定泛型