TypeScript
核心
类型注解
TypeScript
里的类型注解是一种轻量级的为函数或变量添加约束的方式。
function greeter(person: string) {
return "Hello, " + person;
}
let user = "Jane User";
document.body.innerHTML = greeter(user);
TypeScript
支持的类型注解包括:
number
: 表示数字类型。string
: 表示字符串类型。boolean
: 表示布尔类型。any
: 表示任意类型,关闭类型检查。void
: 表示没有返回值的函数。null
和undefined
: 表示空值或未定义的值。never
: 表示永不存在的值的类型(例如,一个总是抛出异常的函数的返回类型)。类型[]
: 表示一个元素类型已知的数组。typescript let numbers: number[] = [1, 2, 3]
Array<类型>
: 使用泛型表示数组。let strings: Array<string> = [‘a’, ‘b’, ‘c’];
- 元组类型注解:
typescript let tuple: [string, number] = [‘hello’, 10];
- 对象类型注解:
typescript let person: { name: string; age: number } = { name: ‘Alice’, age: 25 };
TypeScript
有很强的类型推断能力,在很多情况下,不需要显示注解,编译器会自动推动他们。
typescript let age = 25; // 推断为 number 类型 let name = ‘Alice’; // 推断为 string 类型
思考
使用 TypeScript
的好处:
- 提高代码的可读性和可维护性。使得代码的意图更加明确,可以通过类型注解快速理解他们应该如何被使用;
- 静态类型检查。在编译时会进行类型检查,意味着许多错误在代码运行之前就能捕获到。
- 类型安全。确保变量不会被赋予不合适的值,这在大型项目中尤其重要。
当然 TypeScript
也存在一些缺点,直接引用阮一峰的总结:
(1)丧失了动态类型的代码灵活性。
动态类型有非常高的灵活性,给予程序员很大的自由,静态类型将这些灵活性都剥夺了。
(2)增加了编程工作量。
有了类型之后,程序员不仅需要编写功能,还需要编写类型声明,确保类型正确。这增加了不少工作量,有时会显著拖长项目的开发时间。
(3)更高的学习成本。
类型系统通常比较复杂,要学习的东西更多,要求开发者付出更高的学习成本。
(4)引入了独立的编译步骤。
原生的 JavaScript 代码,可以直接在 JavaScript 引擎运行。添加类型系统以后,就多出了一个单独的编译步骤,检查类型是否正确,并将 TypeScript 代码转成 JavaScript 代码,这样才能运行。
(5)兼容性问题。
TypeScript 依赖 JavaScript 生态,需要用到很多外部模块。但是,过去大部分 JavaScript 项目都没有做 TypeScript 适配,虽然可以自己动手做适配,不过使用时难免还是会有一些兼容性问题。
总的来说,这些缺点使得 TypeScript 不一定适合那些小型的、短期的个人项目。
接口
接口的基本用法
接口定义了对象应该具有的属性和方法。
interface Person {
name: string;
age: number;
greet: () => void;
}
const person: Person = {
name: "张三",
age: 30,
greet() {
console.log(`你好,我是${this.name}`);
},
};
可选属性
接口可以定义可选属性,也就意味着这个属性可以不存在:
interface Person {
name: string;
age?: number;
greet?: () => void;
}
const person: Person = {
name: "张三",
};
只读属性
只读属性意味着该属性在对象被创建后不能被修改:
interface Person {
readonly name: string;
age: number;
}
const person: Person = {
name: "张三",
age: 30,
};
person.age = 31; // 正确
person.name = "李四"; // 错误,name 是只读属性
继承
接口可以继承其他接口,创建出新的接口。
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
const square: Square = {
color: "blue",
sideLength: 10,
};
进阶
索引签名
接口可以定义索引签名,用于描述那些通过索引访问的类型。
interface StringArray {
[index: number]: string;
}
const myArray: StringArray = ["Bob", "Fred"];
const secondItem = myArray[1]; // 类型是 string
混合类型接口
TypeScript
的接口可以描述函数和其他对象混合的类型。
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = function (start: number) {} as Counter;
counter.interval = 123;
counter.reset = function () {};
return counter;
}
const c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
思考
TypeScript
中为什么要使用接口?使用接口的好处是什么?
和使用类型注解的目的类似,也是一种人为的编程约束和用法提示,通过定义一个对象应该具有的属性的方法,有助于确保对象遵循特定的结构,从而提高代码的可读性和可维护性。同时也能在编译阶段就捕获到可能出现的错误,使代码更安全也便于维护。
此外因为接口可以被多个类实现,意味着可以定义一个接口在多出使用,有助于促进代码的标准化,提高复用性。