一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
1. 数组和元组
- 数组的类型注解可以为基础类型或者对象类型
- 元组:即元素个数有限的数组,此类型在处理csv文件时较为有用
// 数组的类型注解如下:既可以为基础类型,也可以为对象类型
const arr: (number | string)[] = [1, '2', 3];
const stringArr: string[] = ['a', 'b', 'c'];
const undefinedArr: undefined[] = [undefined];
// type alias 类型别名
type User = { name: string; age: number };
const objectArr: User[] = [
{
name: 'dell',
age: 28
}
];
class Teacher {
name: string;
age: number;
}
const objectArr: Teacher[] = [
new Teacher(),
// 下面这个对象虽然不是Teacher的实例对象,但是只要数据结构和Teacher实例对象的相同就可以
{
name: 'dell',
age: 28
}
];
// 元组 tuple(元组即元素个数有限的数组)
const teacherInfo: [string, string, number] = ['Dell', 'male', 18];
// 元组在处理csv文件时比较有用,如下定义一个数组,数组中每个元素是元组
const teacherList: [string, string, number][] = [['dell', 'male', 19], ['sun', 'female', 26], ['jeny', 'female', 38]];
2. Interface接口
类型别名(type)和接口(interface)的区别:类型别名可以代表基础类型或者对象,而接口只能代表对象。
在typescript中,有一个规范:如果能用接口去表示类型就用接口,实在不行才用类型别名。
// interface 和 type 相类似,但并不完全一致
interface Person {
// readonly name: string; // readonly只读不能修改
name: string;
age?: number; // 接口定义中的?表示该属性可有可无
[propName: string]: any;// 表示可以接收任何额外属性
say(): string; // 这是一个方法,返回值类型是string
}
interface Teacher extends Person {
teach(): string;
}
// 接口除了以上常用的定义变量、方法之外,还可以定义函数类型。如下定义一个函数名为SayHi、参数和返回值均为string类型的函数
interface SayHi {
(word: string): string;
}
const getPersonName = (person: Person): void => {
console.log(person.name);
};
const setPersonName = (person: Teacher, name: string): void => {
person.name = name;
};
const person = {
name: 'dell',
sex: 'male',
say() {
return 'say hello';
},
teach() {
return 'teach';
}
};
getPersonName(person);// 如果是直接传一个{xx:xx}对象字面量参数的话,则不能有多余属性,否则报错。用person变量可以有多余属性,且不会报错。(解决方法:在Person接口定义中加上[propName: string]: any;)
setPersonName(person, 'lee');
class User implements Person { // 类实现接口时,必须给其必须有的变量和方法进行赋值
name = 'dell';
say() {
return 'hello';
}
}
const say: SayHi = (word: string) => {
return word;
};
在编译成js代码后,接口和类型相关的内容会被剔除掉,只是在开发过程中ts会帮助我们做语法提示。
3. 类的定义与继承
class Person {
name = 'dell';
getName() {
return this.name;
}
}
// 类的继承
class Teacher extends Person {
getTeacherName() {
return 'Teacher';
}
// 重写父类中的方法
getName() {
// super代表父类
return super.getName() + 'lee';
}
}
const teacher = new Teacher();
console.log(teacher.getName());
console.log(teacher.getTeacherName());
super的作用:在子类重写父类的方法时,如果需要在重写方法中调用父类的方法,则可以用super代表父类去调用父类的方法。
4. 类中的访问类型和构造器
访问类型
- public:允许我在类的内外被调用
- private:允许在类内被使用
- protected:允许在类内及继承的子类中使用
// private, protected, public 访问类型
class Person {
public name: string;
public sayHi() {
this.name;
console.log('hi');
}
private sayABC() {
this.name;
}
}
class Teacher extends Person {
public sayBye() {
this.sayHi();
}
}
const person = new Person();
person.name = 'dell';
console.log(person.name);
person.sayHi();
构造器
// constructor
// class Person {
// // 传统写法
// // public name: string;
// // constructor(name: string) {
// // this.name = name;
// // }
// // 简化写法(常用)
// constructor(public name: string) {}
// }
// const person = new Person('dell');
// console.log(person.name);
class Person {
constructor(public name: string) {}
}
class Teacher extends Person {
constructor(public age: number) {
super('dell');
}
}
const teacher = new Teacher(28);
console.log(teacher.age);
console.log(teacher.name);
如果父类有构造器,子类在声明构造器时一定要用super手动调用父类的构造器,否则会报错。如果父类没有构造器,也需要调用一个空的super()。
5. Getter和Setter,静态属性
getter and setter
getter and setter起到保护私有变量的作用。一般类的私有变量的命名会以下划线开头
class Person {
constructor(private _name: string) {}
get name() {
return this._name + ' lee';
}
set name(name: string) {
const realName = name.split(' ')[0];
this._name = realName;
}
}
const person = new Person('dell');
console.log(person.name);
person.name = 'dell lee';
console.log(person.name);
readonly
除了上述的用set和get方法来保护私有变量(只能读不能修改)之外,还可以用readonly关键字
// readonly
class Person {
public readonly name: string;
constructor(name: string) {
this.name = name;
}
}
const person = new Person('Dell');
person.name = 'hello'; // 这里会提示报错
console.log(person.name);
静态属性
static是直接挂在类上的,而不是挂在实例上
// 如下是单例模式的例子(单例模式:一个类只允许获取一个这个类的实例)
class Demo {
private static instance: Demo;
private constructor(public name: string) {}
static getInstance() { // static:把方法直接挂在类上,而不是实例上,可以通过类名.xxx去调用
if (!this.instance) {
this.instance = new Demo('dell lee');
}
return this.instance;
}
}
const demo1 = Demo.getInstance();
const demo2 = Demo.getInstance();
console.log(demo1.name);
console.log(demo2.name);
6. 抽象类
抽象类只能被继承,不能被实例化。且继承的时候必须实现所有抽象方法。
抽象类和接口有点像,抽象类是把类相关的通用东西抽象出来,而接口可以把对象相关的通用东西抽象出来。
// 抽象类
abstract class Geom {
width: number;
getType() {
return 'Gemo';
}
abstract getArea(): number;
}
class Circle extends Geom {
getArea() {
return 123;
}
}
class Square {}
class Triangle {}
// 以下是interface的继承
interface Person {
name: string;
}
interface Teacher extends Person {
teachingAge: number;
}
interface Student extends Person {
age: number;
}
interface Driver {
name: string;
age: number;
}
const teacher = {
name: 'dell',
teachingAge: 3
};
const student = {
name: 'lee',
age: 18
};
// 通过接口的继承可以简化ts的代码
const getUserInfo = (user: Person) => {
console.log(user.name);
};
getUserInfo(teacher);
getUserInfo(student);