一、TS基础
// Boolean
let isHandSome: boolean = true;
// Number
let age: number = 12;
// String
let realName: string = "gege";
// String
let fullName: string = `A${realName}`;
// undefined
let yes: undefined = undefined;
// null
let no: null = null;
// any,不建议使用any类型,ts失去意义
let tem: any = "sss";
// unknown
function devide(params: unknown) {
return <number>params / 2; // 断言
// return (params as number) / 2; // 断言
}
// void,表示空,没有的意思
function welcome(): void {
console.log("hello");
}
// never,表示值永远不存在
// 1异常
function fn(msg: string): never {
throw new Error(msg);
}
// 2死循环
function f(): never {
while (true) {}
}
// 数组类型
let list: number[] = [1, 2, 3];
list.push(4); // 调用数组方法,加进去的类型要一样
// 元祖类型
let tuple: [number, string] = [1, "2"];
// 函数类型
// TS 定义函数类型需要定义输入参数类型和输出类型。
// 输出类型也可以忽略,因为 TS 能够根据返回语句自动推断出返回值类型。
function add(x: number, y: string) {
return x + y;
}
// 函数没有明确返回值,默认返回void
// 函数表达式
let add1 = (x: number, y: number): number => {
return x + y;
};
// 可选参数
// 参数后加个问号,代表这个参数是可选的,可选参数要放在函数入参的最后面
function add2(x: number, y: number, z?: number): number {
return x + y;
}
// interface(接口)
// TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。
interface Person {
name: string;
age: number;
}
let p1: Person = {
name: "wer",
age: 23,
};
// 可选属性
// 跟函数的可选参数是类似的,在属性上加个 ?,这个属性就是可选的
interface People {
name: string;
age?: number;
}
let p2: People = {
name: "23",
};
// 只读属性
interface Peo {
name: string;
readonly age: number;
}
let p3: Peo = {
name: "23",
age: 2,
};
// interface 描述函数类型
interface ISum {
(x: number, y: number): number;
}
const add3: ISum = (num1, num2) => {
return num1 + num2;
};
// 类
// JS 是靠原型和原型链来实现面向对象编程的,es6 新增了语法糖 class。
// TS 通过 public、private、protected 三个修饰符来增强了 JS 中的类。
class Person1 {
name: string;
constructor(name: string) {
this.name = name;
}
speak() {
console.log(`${this.name} is speaking`);
}
}
const p4 = new Person1("lin");
p4.name;
p4.speak();
// 继承
// 使用 extends 关键字实现继承,定义一个 Student 类继承自 Person 类。
class Student extends Person1 {
study() {
console.log(`${this.name} needs study`);
}
}
const s1 = new Student("lin");
s1.speak();
// super关键字
// 如果 Student 类有自己的属性,就要用到 super 关键字来把父类的属性继承过来。
class Student1 extends Person1 {
grade: number;
constructor(name: string, grade: number) {
super(name);
this.grade = grade;
}
}
const s2 = new Student1("lin", 100);
// public 公有的,一个类里默认所有的方法和属性都是 public。可写可不写,不写默认也是 public。
class Person2 {
public name: string;
public constructor(name: string) {
this.name = name;
}
public speak() {
console.log(`${this.name} is speaking`);
}
}
// private 私有的,只属于这个类自己,它的实例和继承它的子类都访问不到。
class Person3 {
private name: string;
public constructor(name: string) {
this.name = name;
}
public speak() {
console.log(`${this.name} is speaking`);
}
}
const p5 = new Person3("lin");
// p5.name 不能访问,私有
// protected 受保护的,继承它的子类可以访问,实例不能访问,继承他的子类能访问
class Person4 {
protected name: string;
public constructor(name: string) {
this.name = name;
}
public speak() {
console.log(`${this.name} is speaking`);
}
}
const p6 = new Person4("lin");
// p6.name 不能访问,受保护
// static 静态属性,可以理解为是类上的一些常量,实例不能访问。
class Circle {
static pi = 3.14;
public radius: number;
public constructor(radius: number) {
this.radius = radius;
}
public calcLength() {
return Circle.pi * this.radius * 2; // 计算周长,直接访问 Circle.pi
}
}
const c1 = new Circle(10);
// c1.pi 不能访问
// 抽象类(abstract) 只能被继承,但不能被实例化的类
// 抽象类有两个特点:1抽象类不允许被实例化。2抽象类中的抽象方法必须被子类实现
abstract class Animal {
constructor(name: string) {
this.name = name;
}
public name: string;
public abstract sayHi(): void;
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
public sayHi() {
console.log("wang");
}
}
// 多态
// 父类定义一个抽象方法,在多个子类中有不同的实现,运行的时候不同的子类就对应不同的操作
abstract class Animal1 {
constructor(name: string) {
this.name = name;
}
public name: string;
public abstract sayHi(): void;
}
class Dog1 extends Animal {
constructor(name: string) {
super(name);
}
public sayHi() {
console.log("wang");
}
}
class Cat extends Animal {
constructor(name: string) {
super(name);
}
public sayHi() {
console.log("miao");
}
}
// this类型 类的成员方法可以直接返回一个 this,这样就可以很方便地实现链式调用
// 链式调用
class StudyStep {
step1() {
console.log("listen");
return this;
}
step2() {
console.log("write");
return this;
}
}
const s = new StudyStep();
s.step1().step2(); // 链式调用
// 灵活调用子类父类方法
// 在继承的时候,this 可以表示父类型,也可以表示子类型
class StudyStep1 {
step1() {
console.log("listen");
return this;
}
step2() {
console.log("write");
return this;
}
}
class MyStudyStep extends StudyStep1 {
next() {
console.log("before done, study next!");
return this;
}
}
const m = new MyStudyStep();
m.step1().next().step2().next(); // 父类型和子类型上的方法都可随意调用
// implements
interface MusicInterface {
playMusic(): void;
}
class Cellphone implements MusicInterface {
playMusic() {}
}
// 处理公共的属性和方法
interface MusicInterface {
playMusic(): void;
}
class Car implements MusicInterface {
playMusic() {}
}
class Cellphone1 implements MusicInterface {
playMusic() {}
}
二、TS进阶版
// 数值型枚举
// enum Direction {
// Up = 1,
// Down,
// Left,
// Right,
// }
enum Direction {
Up,
Down,
Left,
Right,
}
// export default Direction
// 字符串枚举
enum T {
Up = "Up",
Down = "Down",
Left = "Left",
Right = "Right",
}
// export default T
// 异构枚举
enum BL {
No = "yes",
yes = 12,
}
// export default BL
// 计算型和常量型成员
// 枚举表达式的字面意思(基本上是一个字符串字面量或一个数字字面量)
// 对先前定义的常量枚举成员的引用(可以来自不同的枚举)。
// 一个括号内的常量枚举表达式
// 应用于常量枚举表达式的 +,-,~单项运算符之一
// +,-,*,/,%, <<, >>, >>, &, |, ^ 以常量枚举表达式为操作数的二元运算符
// 如果常量枚举表达式被评估为NaN或Infinity,这是一个编译时错误。
// 在所有其他情况下,枚举成员被认为是计算出来的。
enum FileAccess {
// 常量成员
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// 计算成员
G = "123".length,
}
// export default FileAccess;
// 联合枚举和枚举成员类型
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
let c: Circle = {
kind: ShapeKind.Circle,
// 类型 'ShapeKind.Square' 不能被分配给类型 'ShapeKind.Circle'
radius: 10,
};
// export default c;
// 环境枚举
// 环境枚举是用来描述已经存在的枚举类型的形状。
// 声明语 + 关键词 + 枚举名称
declare enum ChineseZodiac {
rat = 1,
cattle,
tiger,
rabbit,
dragon,
}
// export default ChineseZodiac;
// 声明语 + 修饰符 + 关键词 + 枚举名称
declare const enum ChineseZodiac1 {
rat = 1,
cattle,
tiger,
rabbit,
dragon,
}
// export default ChineseZodiac1
// 联合类型 一个变量既支持 number 类型,又支持 string 类型
let num: number | string;
// 交叉类型 如果要对对象形状进行扩展,可以使用交叉类型 &。
interface Person {
name: string;
age: number;
}
type Student = Person & { grade: number };
// 类型别名(type)
type Name = string; // 基本类型
type arrItem = number | string; // 联合类型
const arr: arrItem[] = [1, "2", 3];
type Person1 = {
name: Name;
};
type Student1 = Person1 & { grade: number }; // 交叉类型
type Teacher = Person1 & { major: string };
type StudentAndTeacherList = [Student1, Teacher]; // 元组类型
const list: StudentAndTeacherList = [
{ name: "lin", grade: 100 },
{ name: "liu", major: "Chinese" },
];
// type和interface区别
// 相同点
// 1、都可以定义一个对象或函数
// 2、都允许继承
// interface 继承 interface
interface Person2 {
name: string;
}
interface Student2 extends Person2 {
grade: number;
}
// type 继承 type
type Person3 = {
name: string;
};
type Student3 = Person3 & { grade: number }; // 用交叉类型
// interface 继承 type
type Person4 = {
name: string;
};
interface Student4 extends Person4 {
grade: number;
}
// type 继承 interface
interface Person5 {
name: string;
}
type Student5 = Person5 & { grade: number }; // 用交叉类型
// interface 使用 extends 实现继承, type 使用交叉类型实现继承
// 不同点
// interface(接口) 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。
// type 是类型别名,用于给各种类型定义别名,让 TS 写起来更简洁、清晰。
// type 可以声明基本类型、联合类型、交叉类型、元组,interface 不行
// interface可以合并重复声明,type 不行
interface Person6 {
name: string;
}
interface Person6 {
// 重复声明 interface,就合并了
age: number;
}
const person: Person6 = {
name: "lin",
age: 18,
};
type Person7 = {
name: string;
};
type Person7 = {
// 重复声明 type,就报错
age: number;
};
const person1: Person7 = {
name: "lin",
age: 18,
};
// 类型保护(typeof判断)
function getLength(arg: number | string): number {
if (typeof arg === "string") {
return arg.length;
} else {
return arg.toString().length;
}
}
//类型断言(1.值 as 类型 2.<类型>值,jsx不允许)
function getLength1(arg: number | string): number {
const str = arg as string;
if (str.length) {
return str.length;
} else {
const number = arg as number;
return number.toString().length;
}
}
// 字面量类型
type ButtonSize = "mini" | "small" | "normal" | "large";
type Sex = "男" | "女";
// 泛型 泛型的语法是 <> 里写类型参数,一般可以用 T 来表示。
// 处理函数参数
function print<T>(arg: T): T {
console.log(arg);
return arg;
}
// type写法
type Print = <T>(arg: T) => T;
const printFn: Print = function print(arg) {
console.log(arg);
return arg;
};
// interface写法
interface Iprint<T> {
(arg: T): T;
}
function print<T>(arg: T) {
console.log(arg);
return arg;
}
const myPrint: Iprint<number> = print;
// 默认参数
interface Iprint<T = number> {
(arg: T): T;
}
function print<T>(arg: T) {
console.log(arg);
return arg;
}
const myPrint1: Iprint = print;
// 处理多个函数参数
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
// 函数副作用操作
// 泛型不仅可以很方便地约束函数的参数类型,还可以用在函数执行副作用操作的时候。
// 比如我们有一个通用的异步请求方法,想根据不同的 url 请求返回不同类型的数据。
interface UserInfo {
name: string;
age: number;
}
function request<T>(url: string): Promise<T> {
return fetch(url).then((res) => res.json());
}
request<UserInfo>("user/info").then((res) => {
console.log(res);
});
// 约束泛型
interface ILength {
length: number;
}
function printLength<T extends ILength>(arg: T): T {
console.log(arg.length);
return arg;
}
// 泛型约束类 特别注意的是,泛型无法约束类的静态成员。
class Stack<T> {
private data: T[] = [];
push(item: T) {
return this.data.push(item);
}
pop(): T | undefined {
return this.data.pop();
}
}
// 泛型约束接口
interface IKeyValue<T, U> {
key: T;
value: U;
}
const k1: IKeyValue<number, string> = { key: 18, value: "lin" };
const k2: IKeyValue<string, number> = { key: "lin", value: 18 };
// 泛型定义数组
const arr1: number[] = [1,2,3]
const arr2: Array<number> = [1,2,3]