面试题答案
一键面试类声明的值和类型相互作用及类型安全
- 类型声明:在TypeScript中,类声明既定义了值(实例),也定义了类型。类的属性和方法在声明时指定类型,这使得编译器能够在编译阶段检查类型的正确性。例如,如果一个类
Animal
有一个name
属性且类型为string
,那么任何试图给name
赋非字符串值的操作都会被编译器报错。 - 继承关系中的类型安全:当存在类继承关系时,子类必须满足父类的类型契约。子类可以扩展父类的属性和方法,但不能改变它们的类型(除非使用更具体的类型)。例如,若
Dog
类继承自Animal
类,Dog
类的实例必须具有Animal
类定义的所有属性和方法,并且类型要兼容。 - 泛型的作用:泛型允许我们在类声明中定义类型变量,从而在使用类时指定具体的类型。这增强了代码的复用性和类型安全性。例如,一个
Stack<T>
类可以存储任何类型T
的数据,但在使用时,比如const stack = new Stack<number>()
,编译器就会确保stack
只能操作number
类型的数据。
代码示例
// 定义一个泛型类
class Node<T> {
value: T;
next: Node<T> | null;
constructor(value: T) {
this.value = value;
this.next = null;
}
}
// 定义一个链表类,包含多个Node节点
class LinkedList<T> {
head: Node<T> | null;
constructor() {
this.head = null;
}
add(value: T) {
const newNode = new Node(value);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
}
getValues(): T[] {
const values: T[] = [];
let current = this.head;
while (current) {
values.push(current.value);
current = current.next;
}
return values;
}
}
// 使用链表类操作复杂数据结构
const numberList = new LinkedList<number>();
numberList.add(1);
numberList.add(2);
numberList.add(3);
const numbers = numberList.getValues();
console.log(numbers); // 输出: [1, 2, 3]
const stringList = new LinkedList<string>();
stringList.add('a');
stringList.add('b');
stringList.add('c');
const strings = stringList.getValues();
console.log(strings); // 输出: ['a', 'b', 'c']
在上述代码中,Node
类和LinkedList
类都使用了泛型T
,使得它们可以存储任何类型的数据。通过在使用时指定具体类型(如number
或string
),编译器可以确保对链表的操作都是类型安全的。