Typescript笔记
本文最后更新于:2022年9月23日 下午
0.概述
本来报道之前看过一段时间Typescript,暑假又接受了“锻炼”,然后这几天仿佛无所事事(其实有事)。找闫明洋师兄聊天,师兄问了我一个Typescript的面试题,interface和type两者有什么区别。我才意识到之前看的比较快,细枝末节都略过了,所以这篇笔记记录自己想记的地方,不一定按顺序组织了。
1.基础类型
字符串
注意模版字符串的使用
1
2
3
4
5
6
7let name: string = `Gene`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ name }.I'll be ${ age + 1 } years old next month.`;
//等于
let sentence: string = "Hello, my name is " + name + ".\n\n" +
"I'll be " + (age + 1) + " years old next month.";
//写很长,一直加,不美观
数组
两种方式
- ```typescript let list: number[] = [1, 2, 3];
1
2
3
+ ```typescript
let list: Array<number> = [1, 2, 3];
- ```typescript let list: number[] = [1, 2, 3];
元组
“数”组中可以定义不同类型的元素
1
2
3
4let x:[string,number];
x=['zifuchuan',456];
//必须按照声明的元组类型进行初始化
//对元组中数据进行操作的时候,操作的方法必须和操作的元组对象对应当对元组中新数据进行赋值的时候
1
2x[3]='World';
//x[3]可以赋值为(string|number)类型,x[4]=true;报错,x中没有布尔型
枚举
很友好,用起来很舒服
1
2enum Color {Red, Green, Blue}
let c: Color = Color.Green;可以选择手动赋值、加序号
1
2
3
4enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
enum Color {Red = 2, Green=4, Blue=5}
let c: Color = Color.Green;
any
已知数组的一部分值,可以用
不清楚值是什么类型的时候可以用
1
2let list: any[] = [1, true, "free"];
list[1] = 100;
类型断言
有的时候类型不通过,强制告诉编译器这个类型是我指定的类型
两种方式
- ```typescript let someValue: any = "this is a string"; let
strLength: number = (
someValue).length; //<> 尖括号写法 1
2
3
4
5
+ ```typescript
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;\
//as写法
- ```typescript let someValue: any = "this is a string"; let
strLength: number = (
2.有关接口
概念
Typescript会对值所具有的结构进行检查传入的对象参数实际上会包含很多数学
- 但是编译器只会检查那些必要的属性和定义的类型是否匹配
- 类检查器不会去检查属性的顺序,只需要相应的属性存在并且类型符合就行
1
2
3
4
5
6
7
8
9interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
//只要这个label属性存在就行了
可选属性
用
?解决1
2
3
4
5
6
7
8interface SquareConfig{
color?:string;
width?:number;
}
function createSquare(config:SquareConfig):(color:string,area:number){...}
// createSquare函数,接收SquareConfig类型的参数,返回参数类型为:{color:string,area:number};
let mySquare = createSquare({color:'black'}) as SquareConfig;
// 使用as,将createSquare()函数的返回值类型强制转化为SquareConfig,赋值给mySquare
只读属性
用
readonly解决1
2
3
4
5
6
7
8
9
10
11
12
13interface Point{
readonly x:number;
readonly y:number;
}
let p1:Point ={x:10,y:20};
p1.x=5; //错误 只能读取,不能修改(重新赋值)
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a; //ReadonlyArray相当于readonly的二维实现
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!和
const的区别const用来声明变量readonly用来声明属性
接口继承
implemens关键字继承接口1
2
3
4
5
6
7
8
9
10
11
12
13
14
15interface firstClock{
hours:number;
}
interface secondClock{
minutes:number;
}
interface trueClock implements fisrtClock,secondClock{
seconds:number
}
let time = <trueClock>{};
time.hours=12;
time.minutes=32;
time.seconds=17;extends关键字继承类- 会继承类的成员但不包括其实现,接口中类的成员只能由这个类的子类实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control implements SelectableControl {
select() { }
}
class TextBox extends Control {
select() { }
}
// 错误:“Image”类型缺少“state”属性。
class Image implements SelectableControl {
select() { }
}
class Location {
}
3.有关类
就正常定义
1
2
3
4
5
6
7
8
9
10
11class People{
name:string;
age:number;
constructor(enterName:string,enterAge:number){
this.name = enterName;
this.age = enterAge;
}
study():void{
console.log(`I have been studied for ${this.age} years`);
}
}但是继承的时候要理解一下原理
- 一个是附加属性的加入,和父类中一样的属性要放在
super()里给父类调用 super()表示父类的构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43class animal {
name: string;
constructor(enterName: string) {
this.name = enterName;
}
func(): void {
console.log('我的名字叫:' + this.name);
}
}
class dog extends animal {
age: number; //子类中新添加的属性
constructor(enterDogName: string, enterAge: number) {
super(enterDogName); //调用父类的构造函数,
//调用子类实例的时候(name,age),name属性是父类中有的,用super()去调用父类的构造函数
this.age = enterAge;
//新添加的属性,需要用this关键字
//this关键字必须在super()函数后面
}
//重写override 父类中的方法 函数名、参数一样,代码不一样
func(): void {
console.log('This is a Dog and I override parent\'s name');
}
}
//同理
class human extends animal {
age: number;
language: string;
constructor(enterName: string, enterAge: number, enterLanguage: string) {
super(enterName);
this.age = enterAge;
this.language = enterLanguage;
}
func(): void {
console.log('I am human and I can say' + this.language);
}
}
let pe1 = new human('zly', 28, 'CHN');
//前两个参数都给传到子类human的constructor里,'zly'再传给super()
pe1.func();- 一个是附加属性的加入,和父类中一样的属性要放在
关键词
public
- 程序里定义的所有成员都可以访问
protected
- 程序里定义的成员阿崽派生类(子类)中仍然可以访问
private
不能在声明它的类外部访问
使用
get、set关键字进行访问(存取器)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24let passcode = "secret passcode";
class Employee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}
抽象类
不能直接被实例化
可以包含实现细节,但具体实现必须在子类中有体现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35abstract class Department {
constructor(public name: string) {
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必须在派生类中实现
}
class AccountingDepartment extends Department {
constructor() {
super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在
let newDepartment = new Department();
newDepartment.generateReports()//可以的
4. 函数
分类
命名函数
1
2
3function add(x,y){
return x+y;
}匿名函数
1
2
3let myAdd = function(x,y){
return x+y;
}完整的函数类型
1
2
3
4let myAdd:(x:number,y:number)=>number=
function(x:number,y:number):number{
return x+y;
}
用法
可选参数
1
2
3function myAdd(x:number,y:number,z?:number):number{
return x+y+z;
}初始默认值
1
2
3function buildName(firstName:string,secondName='Ling yi'){
return firstName+secondName;
}剩余参数
不知道有多少个变量、想同时操作多个变量的时候使用
Typescript自动创建参数数组1
2
3
4function buildName(firstName:string,secondName:string,...restofName:string[]){
return firstName+secondName+restofName.join("");
}
// 编译器创建参数数组,名字是你在省略号( ...)后面给定的名字,你可以在函数体内使用这个数组。函数中的this
独立调用对象中的方法需要注意
this关键字的使用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26let deck = {
suits: ["hearts", "spades", "clubs", "diamonds"],
cards: Array(52),
createCardPicker: function() {
//返回一个函数
// return function() {
// let pickedCard = Math.floor(Math.random() * 52);
// let pickedSuit = Math.floor(pickedCard / 13);
// return {suit: this.suits[pickedSuit], card: pickedCard % 13};
//这里的this是指当前窗口window
// }
return ()=> {
//箭头函数能保存函数创建时的 this值,而不是调用时的值
let pickCard = Math.floor(Math.random()*52);
let pickedSuit = Math.floor(pickCard/13);
return {suit:this.suits[pickedSuit],card:pickCard%13};
}
}
}
let cardPicker = deck.createCardPicker();
let pickedCard = cardPicker(); //报错
alert("card: " + pickedCard.card + " of " + pickedCard.suit);方法的重载overload 允许不同参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35let suits = ["hearts", "spades", "clubs", "diamonds"];
// pickCard方法重载
function pickCard(x: {suit: string; card: number; }[]): number;
//提供type {suit: string; card: number; }[] 也就是object
function pickCard(x: number): {suit: string; card: number; };
//提供type number 也就是number
function pickCard(x): any {
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
//因为有了重载函数,可以输入两种预先重载的参数,然后在主函数中进行判断
//根据参数类型进行相应的操作
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length);
return pickedCard;
}
// Otherwise just let them pick the card
else if (typeof x == "number") {
let pickedSuit = Math.floor(x / 13);
return { suit: suits[pickedSuit], card: x % 13 };
}
}
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }];
let pickedCard1 = myDeck[pickCard(myDeck)];
//输入卡片
console.log("card: " + pickedCard1.card + " of " + pickedCard1.suit);
let pickedCard2 = pickCard(15);
//输入数字
console.log("card: " + pickedCard2.card + " of " + pickedCard2.suit);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function overF(enterNum: number): number;
function overF(enterStr: string): string;
function overF(enter): any {
if (typeof enter == "string") {
console.log(enter);
}
if (typeof enter == 'number') {
console.log('这是数字' + enter);
}
}
overF('sssss');
overF(123);
5.泛型
提供一个类型变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34function fn<T>(para: T) {
return para;
}
//可以不指定泛型
let result1 = fn(10);
//指定泛型
let result2 = fn<string>('123');
function fn2<T, K>(para1: T, para2: K) {
console.log(para1);
return para2;
}
//可以同时指定两个泛型
let result3 = fn2<number, string>(123, 'hello');
interface Inter {
length: number;
}
//泛型继承接口,泛型T必须是Inter的一个实现类
function fn3<T extends Inter>(a: T) {
return a.length;
}
//泛型实现类
class MyClass<T>{
name: T;
constructor(name: T) {
this.name = name;
}
}
const mc = new MyClass('hello');
Typescript笔记
https://anonymouslosty.ink/2022/09/21/Typescript笔记/