目录
问题3 TypeScript 中 any、unknown 和 never 之间的区别?
问题21 TypeScript 类中的公共、私有和受保护是什么?
问题22 TypeScript 中引用类时的 readonly 关键字是什么?
问题1 什么是 TypeScript?
TypeScript 是 JavaScript 的一个超集,您可以在其中向 JavaScript 添加类型。JavaScript 是一种松散类型的语言,这会导致生产代码中出现许多类型错误。使用 TypeScript,开发人员甚至可以在运行代码之前捕获这些错误。
问题2 什么是显式和隐式类型分配?
显式意味着写出类型。如下所示:
let name: string = "张三";
隐式意味着 TypeScript 将根据值猜测类型。如下所示,类型将被视为数字
let age = 41;
问题3 TypeScript 中 any、unknown 和 never 之间的区别?
any 类型用于分配任何类型的变量。即使您重新分配另一种类型,也不会出错。如下所示:
let x: any = 10;
x = 'hello'; // No TypeScript error
console.log(x.toUpperCase()); // No TypeScript error
类型 unknown 比类型 any 更好,因为它要求我们在对值执行操作之前检查类型。如下所示:
let y: unknown = 10;
// 使用 y 作为数字
if (typeof y === 'number') {
console.log(y.toFixed(2));
}
该类型 never 表示永远不会发生的值。它通常用于无法正确返回的函数的返回语句。如下所示:
function throwError(message: string): never {
throw new Error(message);
}
问题4 如何给出数组的类型?
对于类型数组,我们需要给出如下类型。在下面的例子中,数组只能包含字符串类型。
const names : string [] = [ "张三" , "李四" , " 王五" ];
names.push ( "赵六" ); // 无错误
我们还可以使用 readonly 关键字,以防止数组被更改。
const names: readonly string[] = ["张三", "李四", "王五"];
names.push("赵六"); // 错误:类型readonly string[]上不存在属性push。
问题5 数组中的类型推断是什么?
如果我们不给数组指定任何类型,它将推断其类型。如下所示:
const numbers = [1, 2, 3]; // 推断为类型 number[]
numbers.push(4);
问题6 什么是元组?
它是一个具有预定义长度和类型的类型数组。它在提供具有不同类型的混合数组类型时非常有用,如下所示:
let ourTuple: [number, boolean, string];
// 正确初始化
ourTuple = [5, false, '这里写点。。。'];
问题7 什么是只读元组?
如果我们不将元组设为只读,我们可以向定义的元组添加更多项目,而 TypeScript 不会抛出任何错误,如下所示:
let ourTuple: [number, boolean, string];
// 正确初始化
ourTuple = [5, false, '这里写点。。。'];
//不安全
ourTuple.push('增加点。。。');
现在,为了修复它,我们在类型前使用关键字 readonly。
let ourTuple: readonly [number, boolean, string];
ourTuple = [5, false, '这里写点。。。'];
// 由于是只读,因此引发错误
ourTuple.push('Coding Hero took a day off');
问题8 如何给出对象的类型?
我们可以通过创建另一个对象(如结构)并指定对象中的键和键的类型来给出对象的类型。
const car: { brand: string, model: string, year: number } = {
brand: "华为",
model: "pura 70",
year: 2024
};
问题9 如何在对象中拥有可选属性?
要提供可选属性或键,我们需要在键后添加 ?,如下所示。
const car: { brand: string, model: string, year?: number } = {
brand: "华为",
model: "pura 70"
};
问题10 解释 TypeScript 中的枚举?
枚举是一种常量变量。您只能使用其中的值。默认情况下,值是数字,从 0 开始并以 1 为增量。
enum allDirections { North, East, South, West }
let currentDirection = allDirections.North;
console.log(currentDirection);
// logs 0
问题11 什么是字符串枚举?
如果您希望枚举包含字符串而不是默认数字,则需要指定相同的内容。
enum allDirections {
North = "北",
East = "东",
South = "南",
West = "西"
};
let currentDirection = allDirections.North;
console.log(currentDirection);
// logs "北"
问题12 什么是类型别名?
它们允许使用自定义名称定义类型,并且可以用于所有原始类型(如字符串和数字)以及复杂类型(如对象和数组)。如下所示:
type Year = number
type Type = string
type Model = string
type Car = {
year: Year,
type: Type,
model: Model
}
const carYear: Year = 2024
const carType: Type = "幻影"
const carModel: Model = "劳斯莱斯"
const car: Car = {
year: Year,
type: Type,
model: Model
};
问题13 什么是接口?
接口类似于类型,但只能用于对象。如下所示:
interface Square {
length: number
}
const square: Square {
length: 20
}
问题14 如何扩展接口?
可以使用 extend 关键字来扩展接口。如下所示:
interface Square {
length: number
}
interface ColorSquare extends Square {
color: string
}
const square: ColorSquare {
length: 20,
color: blue
}
问题15 什么是联合类型?
当属性可以有多个值(如字符串或数字)时,使用联合类型。因此,它们也称为 OR,使用 | 符号。如下所示:
function printSucessCode(code: string | number) {
console.log(`成功码 ${code}.`)
}
printSucessCode(200);
printSucessCode('200');
问题16 如何在函数中给出返回类型?
我们可以在函数名称后使用 : 符号来指定函数的返回类型。如下所示:
function getSum(): number {
return 24;
}
function printMessage(): void {
console.log("欢迎");
}
问题17 如何在函数中给出参数类型?
function sum(a: number, b: number) {
return a + b;
}
问题18 如何在函数中提供可选参数、默认参数和其余参数?
使用默认参数,我们可以将参数标记为可选。像这样,其中 c 是可选的,用 ? 表示。
function substract(a: number, b: number, c?: number) {
return a - b -(c || 0);
}
默认值(ES6 功能)位于类型之后/如下所示:
function multiply(a: number, b: number=10) {
return a * b;
}
其余参数(ES6 功能)被赋予数组类型,因为它们转换数组中传递的项目。如下所示:
function add(a: number, b: number, ...rest: number[]) {
return a + b + rest.reduce((acc, curr) => acc+ curr, 0);
}
问题19 TypeScript 中的转换是什么?
强制转换是覆盖变量类型的过程。如下例所示,类型未知,但在使用 as 关键字时会变成字符串。
let y: unknown = '欢迎';
console.log((y as string).length);
我们也可以用 <> 代替 as。两者意思相同。
let y: unknown = '欢迎';
console.log((<string>y).length);
问题20 如何在类中给出变量的类型?
在这个简单的例子中,我们在类中将名称的类型指定为字符串。
class Developer {
name: string;
}
const dev = new Developer();
dev.name = "张三";
问题21 TypeScript 类中的公共、私有和受保护是什么?
以下是所有内容的含义
-
public — 如果未提及则为默认值,并允许从任何地方访问类成员。
-
private- 类成员只能从类内部访问。
-
protected — 类成员可以由其自身或继承的类访问。
public示例:
class Developer {
public name: string;
}
const dev = new Developer();
dev.name = "张三";
private 的示例。请注意,get 函数来访问 private 成员。
class Developer {
private name: string;
public constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
}
const dev = new Developer("张三");
console.log(person.getName());
我们也可以编写上述的简写版本,即直接在构造函数中添加私有变量。
class Developer {
public constructor(private name: string) {}
public getName(): string {
return this.name;
}
}
const dev = new Developer("张三");
console.log(person.getName());
对于受保护的,我们需要从基类继承,使用 extends 关键字即可。此外,我们还可以使用 implements 关键字从接口获取类的数据。
interface Shape {
getArea: () => number;
}
class Rectangle implements Shape {
public constructor(protected width: number, protected height: number) {}
public getArea(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
public constructor(width: number) {
super(width, width);
}
}
const mySq = new Square(20);
console.log(mySq.getArea()); //Logs 400
问题22 TypeScript 中引用类时的 readonly 关键字是什么?
readonly 关键字可防止类成员被更改。我们通常将 readonly 与私有或受保护成员一起使用。
在下面的例子中,名称在初始定义之后不能更改。
class Developer {
private readonly name: string;
public constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
}
const dev = new Developer("张三");
console.log(person.getName());
问题23 如何在 TypeScript 类中实现覆盖?
覆盖是一个重要的 OOP 概念,继承的类会覆盖其父类中的函数(大多数情况下)。我们通过在函数中使用 override 关键字来实现相同的功能。
interface Shape {
getArea: () => number;
}
class Rectangle implements Shape {
public constructor(protected readonly width: number, protected readonly height: number) {}
public getArea(): number {
return this.width * this.height;
}
public toString(): string {
return `矩形宽度为 ${this.width} 且高度为 ${this.height}`;
}
}
class Square extends Rectangle {
public constructor(width: number) {
super(width, width);
}
public override toString(): string {
return `正方形宽度 ${this.width}`;
}
}
const square = new Square(20);
console.log(square.toString());
问题24 什么是抽象类?
当我们用 abstract 关键字声明基类时,我们不能为其创建对象。在这种方法中,我们通常在子类中使用抽象类的方法。
另外,如果我们在基类中的函数前面添加 abstract 关键字,则需要在子类中创建它。但对于非抽象函数则不需要这样做。
abstract class Polygon {
public abstract getArea(): number;
public toString(): string {
return `多边形面积 ${this.getArea()}`;
}
}
class Rectangle extends Polygon {
public constructor(protected width: number, protected height: number) {
super();
}
public getArea(): number {
return this.width * this.height;
}
}
const rect = new Rectangle(10,20);
console.log(rect.getArea()); // Logs - 200
console.log(rect.toString());// Logs - 多边形面积 200
问题25 什么是 Singleton 类。
Singleton 类是特殊类型的类,用于确保我们只有一个类的实例。
为了创建此类,我们将构造函数设为私有,以防止使用 new 来创建对象。接下来,我们使用静态方法创建该类的单个实例。示例如下:
class Coder {
private static instance: Coder;
private constructor() {}
static getInstance() {
if (this.instance) {
return this.instance;
}
this.instance = new Coder();
return this.instance;
}
}
const c1 = Coder.getInstance();
const c2 = Coder.getInstance();
console.log(c1 === c2); //Logs - true
问题26 TypeScript中的泛型是什么
泛型允许创建类型变量,这些变量可用于创建类、函数和类型别名。在这里,我们不必定义它们使用的类型。
函数示例:
function createArray<S, T>(v1: S, v2: T): [S, T] {
return [v1, v2];
}
console.log(createArray<string, number>('JS', 42)); //Logs - ['JS', 42]
类示例:
class GenericClass<T> {
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
const value = new GenericClass<number>('theNum');2
value.setValue(10);
console.log(value.toString()); // theNum: 10
问题27 什么是 Partial
Partial 将对象中的所有属性更改为可选。在下面的示例中,界面具有宽度和高度。但是,我们只给出了宽度,因为我们已将 rectPart 设为 Partial。
interface Rectangle {
width: number;
height: number;
}
let rectPart: Partial<Rectangle> = {};
rectPart.width = 100;
console.log(rectPart); // Logs - { width: 100 }
问题28 什么是Required
Required将对象中的所有属性更改为必需。在下面的示例中,接口中的里程是可选的。但是,当我们在创建对象时将其设为必需时,我们被迫提供里程。
interface Car {
make: string;
model: string;
mileage?: number;
}
let myCar: Required<Car> = {
make: '劳斯莱斯',
model: '幻影',
mileage: 20 // 强制定义
};
console.log(myCar); // Logs - { make: '斯', model: '幻影', mileage: 20 }
问题29 什么是Record
Record是定义对象的快捷方式,具有指定的键类型和值类型。
const nameAgeObj: Record<string, number> = {
'张三': 42,
'李四': 41
};
console.log(nameAgeObj);// Logs - { 张三: 42, 李四: 41 }
问题30 什么是 Omit
Omit 会从任何对象类型中删除键。如以下示例所示,omit 已从类型中删除 age 和 location,但无法定义。
interface Coder {
name: string;
age: number;
location?: string;
}
const nabs: Omit<Coder, 'age' | 'location'> = {
name: '张三'
};
console.log(nabs); // Logs - { name: '张三' }
问题31 什么是 Pick
Pick 会从任何对象中删除除指定键之外的所有键。如以下示例所示,pick 已从类型中删除 age 和 location,但无法定义。
interface Coder {
name: string;
age: number;
location?: string;
}
const nabs: Pick<Coder, 'name'> = {
name: '张三'
};
console.log(nabs); // Logs - { name: '张三' }
问题32 什么是排除
排除用于从联合中删除类型。如以下示例中所示,布尔值无法使用,因为它已被排除。
type Marks = string | number | boolean;
const value: Exclude<Marks, boolean> = '56';
console.log(typeof value); // Logs - string
问题33 什么是只读
Readonly 用于创建一旦赋值就无法修改的类型。如下例所示,一旦我们为 person 对象赋值,就无法更改。
interface Person {
name: string;
age: number;
}
const person: Readonly<Person> = {
name: "张三",
age: 42,
};
person.name = 'Parag'; // Logs error
问题34 什么是空值合并
空值合并用于处理 null 或 undefined 时具有回退功能的表达式。它与 ?? 运算符一起使用。
如下例所示,里程可以是数字、空值或未定义。这里,当值为空值或未定义时,我们使用 ?? 使其为 NA。
function showMileage(mileage: number | null | undefined) {
console.log(`Mileage: ${mileage ?? 'NA'}`);
}
showMileage(null); // Logs 'Mileage: NA'
showMileage(0); // Logs 'Mileage: 0'
showMileage(undefined); // Logs 'Mileage: NA'