一、声明语法
1.先声明后赋值
let a:number;
a = 1;
2.声明同时赋值
let a = 1; // 绑定类型为number
let a:number = 1; // 语意明确
3.函数的声明
限制参数,返回值的类型
function num(a:number, b:number): number{
return a+b;
}
二、类型
1.number,string,boolean
2.字面量
限制变量的值就是该字面量的值
let a: 10; // 类型为字面量10, 后面赋值只能赋值10
a = 10;
a = 11; // 报错
let b: 'male' | 'female'; // 表示多个字面量类型
b = 'male';
b = 'female';
b = 'hello'; // 报错
3.联合类型
|连接符可以连接多个类型
let a:number | string;
a = 1;
a = false;
4.any与unknown
any:相当对改变量关闭了ts类型检测,不建议使用
let a; // 默认隐式any
let a:any; // 显示any
a = 1;
a = 'str';
a = false;
unknown: 表示未知类型,在赋值方面与any类似
let a:unknown;
a = 1;
a = 'str';
a = false;
区别:
any: 如果赋值给其他明确类型的变量, 则会把别人也设置为any类型
let a:any;
a = 1;
let b:string;
b = a; // 不会报错,但是会影响b的类型检测
unknown不可以赋值给其他明确类型的变量
let a:unknown;
a=10
a='hello'
let s:string;
s = a; // 会报错,不可以赋值
// 解决方案1
if (typef a === 'string') {
s = a;
}
// 解决方案2
// 类型断言,告诉解析器变量的实际类型
// 语法
// 1.变量 as 类型
// 2.<类型>变量
s = a as string
5.void与never
void: 用来表示空,以函数为例,表示没有返回值的函数
function fn(): void {
}
never: 表示永远不会返回结果
function fn():never {
throw new Error('报错了');
}
6.object
定义对象
{属性名: 类型, 属性名: 类型, ...}
在属性名后面加上?,表示属性是可选的
let a: {name: string, age: number};
a = {name: 'libai', age: 23};
a = {name: 'libai', age: 23, sex: '男'}; // 报错
let a: {name: string, age: number, sex?: string};
a = {name: 'libai', age: 23, sex: '男'};
let a: {name: strin, age: number, [propName: string]: any}; // 表示后面可以追加任何属性
定义函数结构的类型声明
let a: (a:number, b:number) => number;
a = function (n1:number,n2:number):number {
return n1+n2;
}
7.Array
// 语法一
let a: string[];
a = ['a', 'b', 'c'];
// 语法二
let b: Array<number>;
b = [1, 2, 3]
8.元组
元组就是固定长度的数组
let a: [string, number];
a = ['hello', 1];
9.enum 枚举
// 定义一个枚举类
enum Gender{
Male,
Female
}
let a: {
name: string,
gender: Gender
};
a = {
name: 'libai',
gender: Gender.Male
};
10.& 表示类型合集
let a: {name: string} & {age: number};
a = {name: 'libai', age: 20};
11.类型别名
type myType = 1|2|3|4|5;
let a: myType;
a = 1;
三、特殊符
可选属性 ?:
表示该属性或参数为可选项
interface Person {
name: string;
age?: number;
}
let lolo: Person = {
name: "lolo"
}
非空断言操作符 !
let a: string | undefined | null;
let b: string;
a = 'hello';
b = a!; // 非空
链判断运算符 .?
var obj: any = undefined;
if(obj?.name) {}
// 等同于
if(obj && obj.name) {}
空值判断运算符 ??
var value: string | undefined | null = '';
console.log(value ?? 'value为空值'); // 当value为空值时,取默认值
四、编译
tsconfig.json文件
tsconfig.json文件是ts编译器的配置文件,ts编译器可以根据它的信息来对代码进行编译
{
// 用来指定哪些ts文件需要被编译
// ** 表示任意目录
// *表示任意文件
"include": [
'./src/**/*'
],
// 不需要编译的文件目录
// 默认值["node_modules", "bowser_components", "jspm_packages"]
"exclude": [
'./src/**/*'
],
// compilerOptions 编译器的选项
"compilerOptions": {
// 用来指定ts被编译为的ES的版本
// 可选值包括:`es6`、`es5`、`esnext`等
// 如果需要考虑兼容性问题就可以设置为`es5`或更低的版本
// 如果代码是在高版本的现代浏览器或高版本的node端,就可以设置为`esnext`
"target": 'es2015',
// 指定要使用的模块化的规范
"module": 'es2015',
// 用来指定要使用的库,默认不用修改
"lib": [],
// 编译后文件所在的目录
"outDir": './dist',
// 所有全局的代码编译后会合并到改文件输出,一般不怎么使用
"outFile": './dist/app.js',
// 是否编译js文件
"allowJs": true,
// 是否检测js是否符合ts规范
"checkJs": true,
// 是否移除注释
"removeComments": true,
// 不生成编译后的文件
"noEmit": false,
// 当有错误时不生成编译后的文件
"noEmitOnError": true
// 所有严格检查的总开关,包括以下四项
"strict": true,
// 用来编译后的文件是否使用严格模式,默认false
"alwaysStrict": true,
// 是否不允许隐式的any类型
"noImplicitAny": true,
// 不允许不明确类型的this
"noImplicitThis": true
// 严格的检查空值
"strictNullChecks": true
...
}
}
五、类
1.声明与访问
class Person{
// 包含两部分: 属性, 方法
// 定义属性
// 实例属性, 只能通过实例去访问
name: string = 'hello';
readonly age: number = 18;
sayHello() {
console.log('hello world');
}
}
const per = new Person();
console.log(per.name, per.age);
per.sayHello();
per.age = 20; // 报错,属性只读
class Person{
// 包含两部分: 属性, 方法
// 定义属性
// 静态属性,只能通过类访问
static name: string = 'hello';
static age: number = 18;
// static readonly age: number = 18 // 只读
static sayHello() {
console.log('hello world');
}
}
console.log(Person.name, Person.age);
Person.sayHello();
2.类中构造函数与this
class Dog {
name: string;
age: number;
// constructor 构造函数
// 构造函数在对象创建的时候调用
constructor (name: string, age: number) {
// 在实例方法中,this就表示当前的实例
// 在构造函数中,this就是当前新建的那个对象
// 可以通过this向新建的对象添加属性
this.name = name;
this.age =age;
}
bark () {
console.log(this);
}
}
const dog1 = new Dog ('小黑', 4);
const dog2 = new Dog ('小白', 1);
console.log(dog1);
console.log(dog2);
3.类的继承
// 声明一个父类
class Animal {
name: string;
age: number;
constructor (name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello () {
console.log('动物在叫~');
}
}
// 创建一个Dog的类
// 继承Animal类
// 使用继承后, 子类拥有父类所有的属性和方法
class Dog extends Animal {
// 子类中可以定义自己的属性和方法
run() {
console.log('狗在跑~')
}
// 方法重写
// 如果在子类中添加了父类相同的方法,子类的方法会覆盖父类的方法
sayHello() {
console.log('汪汪汪!')
}
}
const dog = new Dog('小黄', 2);
console.log(dog);
dog.sayHello();
4.super关键字
// 声明一个父类
class Animal {
name: string;
constructor (name: string) {
this.name = name;
}
sayHello () {
console.log('动物在叫~');
}
}
class Dog extends Animal {
// super关键字的重点使用
// 当子类中添加自己的构造函数添加自己的属性时,必须要继承父类的构造函数,否则报错
// 使用super()
age:number;
constructor(name: string, age: number) {
super(name);
this.age = age;
}
run() {
console.log('狗在跑~');
super.sayHello();
}
// 方法重写
// 如果在子类中添加了父类相同的方法,子类的方法会覆盖父类的方法
// 如果想继承父类同名方法, 使用super关键字
sayHello() {
super.sayHello();
console.log('汪汪汪!');
}
}
const dog = new Dog('小黄', 2);
console.log(dog);
dog.sayHello();
5.抽象类与抽象方法
// 声明一个父类
// 以abstract开头的类是抽象类
// 抽象类以其他的类区别不大,抽象类不可以用来创建对象
// 抽象类就是专门用来继承的类
// 抽象类可以添加抽象方法
abstract class Animal {
name: string;
constructor (name: string) {
this.name = name;
}
// 以abstract开头的方法是抽象方法
// 抽象方法没有方法体
// 抽象方法只能定义在抽象类中,子类必须要对抽象方法进行重写
abstract sayHello(): void;
}
class Dog extends Animal {
// super关键字的重点使用
// 当子类中添加自己的构造函数添加自己的属性时,必须要继承父类的构造函数,否则报错
// 使用super()
age:number;
constructor(name: string, age: number) {
super(name);
this.age = age;
}
// 必须对抽象方法重写
sayHello() {
console.log('汪汪汪!');
}
}
const dog = new Dog('小黄', 2);
console.log(dog);
dog.sayHello();
6.接口
接口的作用: 用来定义一个类结构
// 描述一个对象类型
// type不可以重复声明
// type myType = {
// name: string,
// age: number
// };
// const obj: myType = {
// name: 'libai',
// age: 10
// };
// 接口用来定义一个类结构
// interface可以重复声明,最终声明为合集
interface myInterface {
name: string,
age: number
}
interface myInterface {
sex: string
}
const obj: myInterface = {
name: 'libai',
age: 10,
sex: '男'
};
类与接口的关系
// 接口中的所有属性都不能有实际的值
// 接口中所有的方法都是抽象方法
interface myInter {
name: string,
sayhi(): void;
}
// 定义类可以使类实现一个接口
// 实现接口就是使类满足接口的要求
class myCalss implements myInter {
name: string;
constructor(name: string) {
this.name = name;
}
sayhi() {
console.log('hello world');
}
}
7.属性的封装
场景: 年龄不可以为小数,该如何限制?
public修饰符: 表示该属性可以在任意的位置访问/修改, 默认值
class Person {
// 默认为public类型
// public name: string;
name: string;
// 默认为public类型
// public age: number;
age: number;
constructor(name: string, age:number) {
this.name = name;
// this.age = age>0 ? age : 18;
this.age = age;
}
}
const per = new Person('小白', 20);
// 可以任意修改类中的属性
// 将会导致对象中的数据变得不安全
per.age = -19;
// 可以读取类中的属性
console.log(per.age);
private修饰符: 表示该属性是私有属性, 私有属性只能在类内部进行访问/修改
class Person {
private name: string;
private 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;
}
// 定义方法用来获取age属性
getAge() {
// 私有属性只能在类内部进行访问
return this.age;
}
// 定义方法修改age属性
setAge(value: number) {
// 私有属性只能在类内部进行修改
if (value > 0) {
this.age = value;
} else {
this.age = 18;
}
}
}
const per = new Person('小白', 20);
// per.name = '小黑'; // 报错, 私有属性只能在类内部进行修改
per.setName('小黑');
// console.log(per.name); // 报错, 私有属性只能在类内部进行访问
console.log(per.getName());
// per.age = -20; // 报错, 私有属性只能在类内部进行修改
per.setAge(-20);
// console.log(per.age); // 报错, 私有属性只能在类内部进行访问
console.log(per.getAge());
class Person {
private _name: string;
private _age: number;
constructor(name: string, age:number) {
this._name = name;
this._age = age;
}
// ts提供了访问器, 代码可以这样写
get name() {
return this._name;
}
set name(value: string) {
this._name = value;
}
get age() {
return this._age;
}
set age(value: number) {
if (value > 0) {
this._age = value;
} else {
this._age = 18;
}
}
}
const per = new Person('小白', 20);
per.name = '小黑';
console.log(per.name);
protect修饰符: 表示该属性是受保护属性, 只能在当前类和当前类的子类中访问与修改
class A {
protected num: number;
constructor(num: number) {
this.num = num;
}
}
class B extends A {
test() {
// 可以访问受保护属性
console.log(this.num);
}
}
const b = new B(10);
b.num = 1; // 报错
类声明的简写形式,语义不明确不建议
// class C {
// name: string;
// age: number;
// constructor(name: string, age: number) {
// this.name = name;
// this.age = age;
// }
// }
class C {
// 可以直接将属性定义在构造函数中
constructor(public name: string, public age:number) {
}
}
const c = new C('小黄', 10);
console.log(c);
8.泛型
// 定义函数或者是类, 如果遇到类型不明确就可以使用泛型
// <T>定义一个泛型T, 先定义后使用
function fn<T>(a: T): T{
return a;
}
// 调用
// 可以直接调用具有泛型的函数
// 手动指定泛型为string
const res = fn<string>('hello');
console.log(res);
指定多个泛型
function fn<T, K>(a: T, b: K): T {
console.log(b);
return a;
}
const res = fn<string, number>('hello', 20);
console.log(res);
T extends Inter 表示泛型T必须是Inter的实现类
interface Inter{
length: number
};
function fn<T extends Inter>(a: T): number {
return a.length;
}
console.log(fn('123));
console.log(fn({length: 5}));