目录
[interface 接口](#interface 接口)
类型声明
在使用javascript时,由于js是一个类型松散的语言,在进行运算、传参等操作时,并不会对类型进行校验,这就导致代码可能会产生运行时错误。
但typescript可以通过类型声明,实现对代码的静态校验,在代码运行之前规避部分报错。
typescript类型
1.boolean 布尔值
2.number 数字(包括整数、小数、二进制、八进制、十六进制、十进制)
3.string 字符串
4.Array<元素类型>、元素类型[] 数组
5.[元素1类型,元素2类型,......] 元组(元组允许表示一个已知元素数量和类型的数组)
6.enum 枚举 使用枚举可以使代码可读性更好,当把一个变量设定为枚举类型时,变量的值需要为枚举值其中之一
枚举类型:
6.1 数字枚举
数字枚举默认从0开始
TypeScript
// 定义数字枚举
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
// 使用枚举
const move: Direction = Direction.Up;
console.log(move); // 输出 0
console.log(Direction.Down); // 输出 1
可以手动规定第一个枚举值,后续枚举值会依次递增
TypeScript
// 从 1 开始递增
enum Status {
Success = 1, // 1
Error, // 2
Loading, // 3
Pending // 4
}
console.log(Status.Success); // 1
console.log(Status.Error); // 2
也可以自定义所有元素的枚举值
TypeScript
enum Priority {
Low = 10,
Medium = 20,
High = 30,
Urgent = 40
}
console.log(Priority.Medium); // 20
console.log(Priority.Urgent); // 40
可以通过下标访问,获取对应下标的key:
TypeScript
enum Color {
Red,
Green,
Blue
}
console.log(Color.Red); // 0(正向映射)
console.log(Color[0]); // "Red"(反向映射)
console.log(Color.Green); // 1
console.log(Color[1]); // "Green"
6.2 字符串枚举
枚举的value除了是数字,也可以是字符串
TypeScript
enum Gender {
Male = "MALE",
Female = "FEMALE",
Other = "OTHER"
}
// 使用
const userGender: Gender = Gender.Male;
console.log(userGender); // "MALE"
// 不支持反向映射
// console.log(Gender["MALE"]); // 错误:字符串枚举没有反向映射
6.3 异构枚举
枚举的value可以既有数字,又有字符串
TypeScript
enum MixedEnum {
No = 0,
Yes = "YES"
}
console.log(MixedEnum.No); // 0
console.log(MixedEnum.Yes); // "YES"
7.any 任意值 如果不希望对某些变量的类型进行静态类型检查,可以给变量定义为any类型。但与any类型进行计算的其他类型也会被覆盖为any,因此any可能会破坏其他类型。可以尽量少使用any。
8.void 空值 表示没有任何类型,void类型可以被赋值为undefined或者null
9.Null
10.undefined
11.never 表示永不存在的值的类型。用于不存在返回值的函数,或者中途会抛出错误的函数,或箭头函数。
never类型变量可以赋值给任何类型,但是任何其他类型都不能赋值给never。
never的例子:
TypeScript
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
断言
有时,对于某个值,编码人员可能清除该值的详细信息,比如该对象上的某个方法等,但typescript会因为不知道其值,而在静态阶段对其进行报错。如果要消除这种报错,可以使用"断言",告知typescript该值一定符合静态审查。
1.<> 断言
用<>表示变量一定可以视作<>内的类型。
TypeScript
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
2.as 断言
使用变量 as 类型,表示变量一定可以被视作某种类型。
TypeScript
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
一般情况下,<>断言和as断言都可以使用,但JSX只支持as断言。
类型别名type
通过type 类别别名 = 类型 的形式,可以给类型起别名,在实际使用时,使用别名表示变量的类型。
1.基础类型别名
TypeScript
// 给 string 类型起别名
type UserName = string;
const name: UserName = "张三";
// 给 number 类型起别名
type Age = number;
const age: Age = 25;
2.联合类型别名
可以用 | 表示 类型可以是其中之一:
TypeScript
// 定义可能是 string 或 number 的类型
type StringOrNumber = string | number;
let value: StringOrNumber;
value = "hello"; // 合法
value = 123; // 合法
3.交叉类型别名
可以用 & 表示,类型是两个别名的合并:
TypeScript
// 合并两个类型的属性
type Person = { name: string };
type Employee = { id: number };
type EmployeePerson = Person & Employee;
const employee: EmployeePerson = {
name: "李四",
id: 1001
};
4.函数类型别名
类型别名也可以定义为函数的形式,规定函数的参数和返回值:
TypeScript
// 定义函数类型
type AddFunction = (a: number, b: number) => number;
const add: AddFunction = (a, b) => a + b;
console.log(add(1, 2)); // 输出 3
interface 接口
interface(接口)的部分用法与type类似,但与type不同的是,interface用于定义对象的类型别名,同时,interface可以定义可选属性与只读属性,且interface定义的对象也可以被看做是类的一种规范,可以用来实现具体的类。
1.基本interface对象
TypeScript
// 定义对象接口
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "赵六",
age: 30
};
2.可选属性与只读属性
在interface中,可以使用readonly定义只读属性,使用description? 定义可选属性:
TypeScript
interface Product {
id: number;
name: string;
price: number;
description?: string; // 可选属性
readonly category: string; // 只读属性
}
const product: Product = {
id: 101,
name: "手机",
price: 5999,
category: "电子产品"
};
3.函数interface
interface定义函数别名:
TypeScript
// 定义函数接口
interface GreetFunction {
(name: string): string;
}
const greet: GreetFunction = (name) => `Hello, ${name}!`;
console.log(greet("孙七")); // 输出 "Hello, 孙七!"
4.类和interface
interface可以用来定义类的"契约或规范",类通过implements关键字来实现定义的接口,从而保证类符合接口定义的结构。
4.1 基本实现
TypeScript
// 定义接口(契约)
interface Animal {
name: string;
eat(food: string): void;
sleep(): void;
}
// 类实现接口
class Dog implements Animal {
// 必须实现接口中的属性
name: string;
constructor(name: string) {
this.name = name;
}
// 必须实现接口中的方法
eat(food: string): void {
console.log(`${this.name}正在吃${food}`);
}
sleep(): void {
console.log(`${this.name}正在睡觉`);
}
// 类可以有接口中未定义的额外方法
bark(): void {
console.log(`${this.name}正在汪汪叫`);
}
}
// 使用
const dog = new Dog("旺财");
dog.eat("骨头"); // 输出:旺财正在吃骨头
dog.sleep(); // 输出:旺财正在睡觉
dog.bark(); // 输出:旺财正在汪汪叫
4.2 类实现多个接口
通过implements 接口1,接口2,...... 的语法进行:
TypeScript
interface Swimmer {
swim(): void;
}
interface Runner {
run(): void;
}
// 类同时实现两个接口
class Person implements Swimmer, Runner {
swim(): void {
console.log("正在游泳");
}
run(): void {
console.log("正在跑步");
}
}
const person = new Person();
person.swim(); // 输出:正在游泳
person.run(); // 输出:正在跑步
4.3 接口继承类
接口也可以继承自类,接口会继承类的所有成员,并可以添加新成员,实现该接口时,实现接口的类必须同时满足接口与接口继承自类的类要求:
TypeScript
// 定义一个类
class Base {
private id: number;
protected name: string;
public age: number;
constructor(id: number, name: string, age: number) {
this.id = id;
this.name = name;
this.age = age;
}
}
// 接口继承类
interface Derived extends Base {
// 接口可以添加新成员
getInfo(): string;
}
// 实现接口的类必须同时满足Base类和Derived接口的要求
class DerivedClass extends Base implements Derived {
constructor(id: number, name: string, age: number) {
super(id, name, age);
}
getInfo(): string {
// 可以访问继承的protected成员name和public成员age
// 但无法访问private成员id
return `姓名: ${this.name}, 年龄: ${this.age}`;
}
}
const obj = new DerivedClass(1, "张三", 25);
console.log(obj.getInfo()); // 输出:姓名: 张三, 年龄: 25