目录
一、TypeScript的基本概念与编译
1.1.基本概念
定义:TypeScript是JavaScript的超集,它继承了JavaScript的全部语法,并添加了一些新的特性,如静态类型检查、类和接口等。这使得TypeScript更适合用于开发大型、复杂的企业级项目。
目的:TypeScript的目的并不是创造一种全新语言,而是增强JavaScript的功能,提高代码的可读性和可维护性。
编译:TypeScript代码需要编译成JavaScript代码才能在浏览器中运行。编译过程会删除类型声明和类型相关的代码,只保留能运行的JavaScript代码。
1.2.TypeScript优缺点
typescript 指的是js的升级版本 其实就是给js添加类型
优点:增强了代码的可维护性,特别是大型项目;友好的快速的能在编辑器中提示错误,在编译阶段就能发现大部分错误;支持最新的JavaScript 的新特性
缺点:需要一定的学习成本和一些插件库不是很兼容;增加了前期的开发成本(开发速度)
tsc 文件名 就是编译ts 文件
tsc --init 生成ts的配置文件
二、TS的基础类型
布尔类型
// ts 声明一个布尔类型
let c:boolean;
//:boolean 类型注解 作用:给变量添加类型约束,约束什么类型 就只能赋值什么类型
c = false
数字类型
// ts 声明数字类型
let a:number;
//声明变量 :number类型注解
a = 200;//赋值
console.log(a);
字符串类型
// ts 声明一个字符串类型
let b:string;
b = "张三";
数组类型
// let arr=[];
// 写法1
// let arr:any[]=[];
// 写法2
// let arr:Array<any> = [];
// 定义数组的一种方式
let a: number[] = [];//只能是数字类型
let b: Array<number> = [];//只能是数字类型
let c: (number | string)[] = [];//既可以是数字类型也可以是字符串
let d: (boolean | string)[] = [];//既可以是布尔类型也可以是字符串
interface PeopleType {
name: string,
age: number,
sex: string
}
// [{ name: "张三", age: 22, sex: "男" }, { hame: "张三", age: 22, sex: "男" }]
//数组对于对象的类型注解
let peoplelList:PeopleType[]= [{name:"张三",age:22,sex:"男"},{name:"张三"
,age:22,sex:"男"}]
export { };
元组类型
// 元组 tuple 表示一个已知数量和类型的数组(特殊数组)
let tup:[number,string,boolean,number] = [1,"222",false,1111];
枚举类型
枚举 enum 用于定义数值的集合,通常用于定义一组有规则的数据 比如周一到周天
枚举 根据存储值不同分为三种:数字枚举、字符串枚举、符合枚举。
1.数字枚举
枚举成员会被赋予一个递增的数字值,默认从0开始
enum Day {
Sunday, // 0
Monday, // 1
Tuesday, // 2
Wednesday, // 3
Thursday, // 4
Friday, // 5
Saturday // 6
}
console.log(Day.Sunday); // 输出: 0
console.log(Day.Monday); // 输出: 1
console.log(Day[2]); // 输出: "Tuesday" (反向映射)
也可以手动赋值,未手动赋值的成员会基于前一个成员的值递增
enum Direction {
Up = 1,
Down, // 2
Left, // 3
Right // 4
}
2.字符串枚举
enum DirectionString {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT"
}
console.log(DirectionString.Up); // 输出: "UP"
console.log(DirectionString["DOWN"]); // 输出: "DOWN" (反向映射)
3.复合枚举
enum MixedEnum {
No = 0,
Yes = "YES",
Maybe = 100,
Absolutely = "ABSOLUTELY"
}
console.log(MixedEnum.No); // 输出: 0
console.log(MixedEnum.Yes); // 输出: "YES"
console.log(MixedEnum[100]); // 输出: "Maybe" (反向映射,仅限于数字到名称)
// console.log(MixedEnum["ABSOLUTELY"]); // 错误:字符串到数字的反向映射不被支持
枚举的高级用法
常量枚举:使用 const enum
可以生成更高效的代码,因为它不会在编译后的 JavaScript 中生成实际的对象。
const enum DirectionConst {
Up,
Down,
Left,
Right
}
let dir: DirectionConst = DirectionConst.Up;
// 编译后的代码不会包含 DirectionConst 对象
枚举成员的类型:枚举成员本身具有类型,并且 TypeScript 会根据上下文自动推断类型
enum ShapeKind {
Circle,
Square
}
function area(shape: ShapeKind) {
return shape === ShapeKind.Circle ? 100 : 200;
}
any类型
用来定义一个不确定的类型,任何值都可以赋值给any
anyscript 不要滥用any 不然 ts 就没有意义了
let age2:any;
age2 = 100;
// age2 ="222";
// age2 = true;
// age2 = undefined
unknown类型
任意类型,类似于any类型,但禁止更改传递的值,即只能被赋值不能传递。
拓展:
unknown 和any 区别任何值都可以赋值给any ,同时any也可以赋值给任意类型
unknown 任何类型都可以赋值给它 但是它本身只能赋值给unknown或any
void类型:用于标识方法返回值的类型,表示该方法没有返回值。
never类型:表示永不返回的值或永远返回error的值。
三、TypeScript的进阶概念
联合类型
联合类型(不是一种类型:可以复制多种类型 )
let age:number|string|boolean;//既可以赋值数字也可以赋值字符串
age = 20;
age = "30"
age = true
类型别名
给联合类型起名字 达到复用的效果
type ageType = number|string|boolean
// let pic:numberstring boolean
let pic:ageType;//类型别名使用
pic = 100;
pic = true;
let prop:ageType;//复用 联合类型
类型推断
当类型没有给出时,TypeScript编译器会利用类型推断来推断变量的类型。
let test = "200";
// test = 300 错误
类型断言
在一些特殊情况下,我们比ts 更清楚我们的变量是归属于什么类型,所以我们可以手动设置类型
let a:any = "张三";
let b1 = (a as string).length;// 类型断言
let b2 = (<string>a).length;// 类型断言
// 非空断言
let c:string|number|undefined|null = "123"
console.log(c!.length);
// 确定赋值断言
// 没有赋值就使用会报错,所以可以通过确定赋值断言来解决
let value!:number;
console.log(value);
export {}
对象(Object)
在 TypeScript 中,对象是通过键值对来定义的,其中键是字符串(或符号),而值可以是任何类型。TypeScript 允许你为对象的属性添加类型注解
let person: { name: string; age: number } = {
name: "Alice",
age: 30
};
接口(interface)
接口(interface)对行为的抽象,具体行为由类实现。接口可以描述对象的形状,包括属性及其类型。
接口的基本用法
接口通过 interface
关键字来定义。下面是一个简单的接口示例,它定义了一个具有 name
和 age
属性的对象结构:
interface Person {
name: string;
age: number;
}
// 使用接口
let tom: Person = {
name: "Tom",
age: 30
};
可选属性
有时候,接口中的某些属性可能不是必需的。在这种情况下,你可以使用 ?
标记这些可选属性:
interface Person {
name: string;
age?: number; // 可选属性
}
let tom: Person = {
name: "Tom"
// age: 30, // 可选属性,可以省略
};
只读属性
如果希望接口中的某个属性在对象被创建后不能被修改,你可以使用 readonly
关键字来标记这个属性
interface Person {
readonly name: string;
age: number;
}
let tom: Person = {
name: "Tom",
age: 30
};
// tom.name = "Jerry"; // 错误:不能给只读属性赋值
tom.age = 31; // 正确:可以修改非只读属性
函数类型
接口不仅可以描述对象的属性,还可以描述对象的函数签名。下面是一个包含函数签名的接口示例:
interface Greeter {
greet(name: string): void;
}
let greeter: Greeter = {
greet(name: string) {
console.log("Hello, " + name + "!");
}
};
greeter.greet("Tom"); // 输出: Hello, Tom!
索引签名
索引签名允许你描述对象上可能存在的属性键和值的类型。这对于描述那些可能具有任意数量属性的对象特别有用
interface StringIndexedArray {
[index: string]: number;
}
let myArray: StringIndexedArray;
myArray["foo"] = 1; // 正确:属性键是字符串,属性值是数字
myArray["bar"] = 2; // 正确
// myArray[3] = "hello"; // 错误:属性键应该是字符串,而不是数字
接口的继承
接口之间可以相互继承,从而可以基于一个接口定义另一个接口,并添加新的属性或函数签名
interface Animal {
name: string;
}
interface Dog extends Animal {
bark(): void;
}
let dog: Dog = {
name: "Rex",
bark() {
console.log("Woof! Woof!");
}
};
类(class)
类:提供了一种更结构化的方式来定义对象的属性和方法。类可以包含构造函数、属性、方法、访问修饰符(如 public
、private
和 protected
)以及继承等特性
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
函数
TypeScript 为函数参数和返回值添加了类型注解
function greet(name: string): string {
return "Hello, " + name;
}
泛型:允许在定义函数、接口或类时不指定具体类型,而在使用时再指定类型的一种机制
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
let numOutput = identity<number>(123);
命名空间(namespace):用于组织代码,避免命名冲突。
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string): boolean {
return /^[A-Za-z]+$/.test(s);
}
}
}
let validator = new Validation.LettersOnlyValidator();
构造器
在 TypeScript 中,构造器(constructor)是与类(class)紧密相关的一个概念。构造器是一个特殊的方法,用于在创建类的新实例时初始化该实例。当使用
new
关键字调用类时,构造器会被自动调用。
构造器基本用法
class Person {
name: string;
age: number;
// 构造器
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 创建 Person 类的新实例
let alice = new Person("Alice", 30);
alice.greet(); // 输出: Hello, my name is Alice and I am 30 years old.
构造器的访问修饰符
构造器可以有访问修饰符,如
public
(默认)、private
或protected
。然而,由于构造器的主要目的是创建类的实例,因此将其设为private
或protected
并不常见,这会导致类不能在类外部被实例化(对于private
)或不能在子类外部被实例化(对于protected
)
class Singleton {
// 私有构造器,防止外部实例化
private constructor() {
// ...
}
// 静态方法提供类的唯一实例
private static instance: Singleton;
public static getInstance(): Singleton {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
// 尝试直接实例化会报错
// let s = new Singleton(); // 错误:构造器是私有的
// 正确获取唯一实例
let s1 = Singleton.getInstance();
let s2 = Singleton.getInstance();
// s1 和 s2 实际上是同一个实例
继承中的构造器
当类被继承时,子类的构造器需要调用父类的构造器,以确保父类被正确初始化。这可以通过在子类构造器中调用
super()
来实现。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
breed: string;
// 子类构造器需要调用父类构造器
constructor(name: string, breed: string) {
super(name); // 调用父类构造器
this.breed = breed;
}
bark() {
console.log("Woof! Woof!");
}
}
let dog = new Dog("Rex", "German Shepherd");
dog.speak(); // 输出: Rex makes a sound.
dog.bark(); // 输出: Woof! Woof!
"文字耕耘实属不易,诚挚期待您的点赞支持。"