系统中没有安装wordpress,外贸网站优化,微信运营网站建设,深圳市建设工程交易服务中心网文章目录 1. 什么是TypeScript2. 类型声明和类型推断的区别#xff0c;并举例应用3. 什么是接口#xff08;interface#xff09;#xff0c;它的作用#xff0c;接口的使用场景。接口和类型别名#xff08;Type Alias#xff09;的区别4. 什么是泛型#xff08;generi… 文章目录 1. 什么是TypeScript2. 类型声明和类型推断的区别并举例应用3. 什么是接口interface它的作用接口的使用场景。接口和类型别名Type Alias的区别4. 什么是泛型generic如何创建泛型函数和泛型类实际用途5. 枚举enum是什么它的优势应用案例。枚举和常量枚举的区别6. 如何处理可空类型nullable types和undefined类型如何正确处理这些类型以避免潜在错误7. 什么是联合类型和交叉类型8. 什么是TypeScript中的声明文件Declaration Files9. 什么是命名空间Namespace和模块Module10. 什么是类型断言Type Assertion11. TypeScript中的可选参数和默认参数是什么12. 类型守卫Type Guards是什么13. 索引类型Index Types是什么好处有什么14. const和readonly的区别15. TypeScript 中 any 类型的作用是什么滥用会有什么后果16. TypeScript中的this有什么需要注意的17. TypeScript数据类型18. interface可以给Function/Array/ClassIndexable)做声明吗19. TypeScript中的协变、逆变、双变和抗变是什么20. TypeScript中的静态类型和动态类型有什么区别21. 介绍TypeScript中的可选属性、只读属性和类型断言22. TypeScript 中的模块化是如何工作的举例说明 结尾 面试题涉及了 TypeScript 语言的各个方面包括基本语法、类型系统、函数、类、模块化、泛型、装饰器等。在面试中常见的 TypeScript 面试题主要围绕以下几个方面展开 类型系统考察对 TypeScript 类型系统的理解包括基本类型、联合类型、交叉类型、接口、类型别名、类型推断、类型守卫等。 函数和类涉及函数参数类型、返回值类型、箭头函数、函数重载、类的定义、继承、访问修饰符等概念。 泛型考察在函数、类和接口中如何使用泛型来增加代码的灵活性和复用性。 模块化问题可能涉及 ES6 模块化的语法、导入导出方式以及模块解析等内容。 装饰器了解对装饰器的使用包括类装饰器、方法装饰器、属性装饰器以及参数装饰器的定义和应用。 编译配置熟悉 tsconfig.json 中的配置选项包括编译目标、模块系统、严格模式等。 工程化实践了解 TypeScript 在项目中的实际应用如与 JavaScript 的混用、第三方库的声明文件使用、类型声明等。 下面是上述涵盖内容的具体面试题
1. 什么是TypeScript
TypeScript是一种由微软开发的开源编程语言它是JavaScript的超集。TypeScript通过添加静态类型、类、接口和模块等功能使得在大型应用程序中更容易进行维护和扩展。它可以被编译为纯JavaScript从而能够在任何支持JavaScript的地方运行。使用TypeScript可以帮助开发人员在编码过程中避免一些常见的错误并提供更好的代码编辑功能和工具支持。
2. 类型声明和类型推断的区别并举例应用
类型声明是显式地为变量或函数指定类型而类型推断是TypeScript根据赋值语句右侧的值自动推断变量的类型。例如
// 类型声明
let x: number;
x 10;
// 类型推断
let y 20; // TypeScript会自动推断y的类型为number3. 什么是接口interface它的作用接口的使用场景。接口和类型别名Type Alias的区别
接口是用于描述对象的形状的结构化类型。它定义了对象应该包含哪些属性和方法。在TypeScript中接口可以用来约束对象的结构以提高代码的可读性和维护性。例如
interface Person {name: string;age: number;
}
function greet(person: Person) {return Hello, ${person.name}!;
}接口和类型别名的区别
接口定义了一个契约描述了对象的形状属性和方法以便在多个地方共享。它可以被类、对象和函数实现。类型别名给一个类型起了一个新名字便于在多处使用。它可以用于原始值、联合类型、交叉类型等。与接口不同类型别名可以用于原始类型、联合类型、交叉类型等而且还可以为任意类型指定名字。
4. 什么是泛型generic如何创建泛型函数和泛型类实际用途
泛型是一种在定义函数、类或接口时使用类型参数的方式以增加代码的灵活性和重用性。在TypeScript中可以使用来创建泛型。例如
function identityT(arg: T): T {return arg;
}
// 调用泛型函数
let output identitystring(hello);5. 枚举enum是什么它的优势应用案例。枚举和常量枚举的区别
枚举是一种对数字值集合进行命名的方式。它们可以增加代码的可读性并提供一种便捷的方式来使用一组有意义的常量。例如
enum Color {Red,Green,Blue
}let selectedColor: Color Color.Red;枚举和常量枚举的区别:
枚举可以包含计算得出的值而常量枚举则在编译阶段被删除并且不能包含计算得出的值它只能包含常量成员。常量枚举在编译后会被删除而普通枚举会生成真实的对象。
6. 如何处理可空类型nullable types和undefined类型如何正确处理这些类型以避免潜在错误
在TypeScript中可空类型是指一个变量可以存储特定类型的值也可以存储null或undefined。通过使用可空类型开发者可以明确表达一个变量可能包含特定类型的值也可能不包含值即为null或undefined。这有助于提高代码的可读性并使得变量的可能取值范围更加清晰明了。
为了声明一个可空类型可以使用联合类型Union Types例如 number | null 或 string | undefined。 例如
let numberOrNull: number | null 10;
numberOrNull null; // 可以赋值为null let stringOrUndefined: string | undefined Hello;
stringOrUndefined undefined; // 可以赋值为undefined7. 什么是联合类型和交叉类型
联合类型表示一个值可以是多种类型中的一种而交叉类型表示一个新类型它包含了多个类型的特性。
联合类型示例
// typescript
let myVar: string | number;
myVar Hello; // 合法
myVar 123; // 合法交叉类型示例
interface A {a(): void;
}
interface B {b(): void;
}
type C A B; // 表示同时具备 A 和 B 的特性8. 什么是TypeScript中的声明文件Declaration Files
声明文件通常以 .d.ts 扩展名结尾用于描述已有 JavaScript 代码库的类型信息。它们提供了类型定义和元数据以便在 TypeScript 项目中使用这些库时获得智能感知和类型安全。
9. 什么是命名空间Namespace和模块Module
模块
在一个大型项目中可以将相关的代码组织到单独的文件并使用模块来导入和导出这些文件中的功能。在一个 Node.js 项目中可以使用 import 和 export 关键字来创建模块从而更好地组织代码并管理依赖关系。
命名空间
在面向对象的编程中命名空间可以用于将具有相似功能或属性的类、接口等进行分组以避免全局命名冲突。这在大型的 JavaScript 或 TypeScript 应用程序中特别有用可以确保代码结构清晰并且不会意外地重复定义相同的名称。
模块提供了一种组织代码的方式使得我们可以轻松地在多个文件中共享代码
命名空间则提供了一种在全局范围内组织代码的方式防止命名冲突。
模块示例:
// greeter.ts
export function sayHello(name: string) {return Hello, ${name}!;
}
// app.ts
import { sayHello } from ./greeter;
console.log(sayHello(John));命名空间示例:
// greeter.ts
namespace Greetings {export function sayHello(name: string) {return Hello, ${name}!;}
}
// app.ts
reference pathgreeter.ts /
console.log(Greetings.sayHello(John));在上面的示例中 使用模块时我们可以使用 export 和 import 关键字来定义和引入模块中的函数或变量。 而在命名空间中我们使用 namespace 来创建命名空间并且需要在使用之前使用 reference pathfile.ts / 来引入命名空间。
10. 什么是类型断言Type Assertion
类型断言允许程序员手动指定一个值的类型。这在需要明确告诉编译器某个值的类型时非常有用。
let someValue: any this is a string;
let strLength: number (someValue as string).length;11. TypeScript中的可选参数和默认参数是什么
可选参数允许函数中的某些参数不传值在参数后面加上问号?表示可选。默认参数允许在声明函数时为参数指定默认值这样如果调用时未提供参数值则会使用默认值。
可选参数示例
function greet(name: string, greeting?: string) {if (greeting) {return ${greeting}, ${name}!;} else {return Hello, ${name}!;}
}默认参数示例
function greet(name: string, greeting: string Hello) {return ${greeting}, ${name}!;
}12. 类型守卫Type Guards是什么
类型守卫是一种用于在运行时检查类型的技术它允许开发人员在特定的作用域内缩小变量的范围以确保正确推断类型。
function isString(test: any): test is string {return typeof test string;
}
if (isString(input)) {// input 在此代码块中被收窄为 string 类型
}13. 索引类型Index Types是什么好处有什么
索引类型允许我们在 TypeScript 中创建具有动态属性名称的对象并且能够根据已知的键来获取相应的属性类型。 好处
1.动态属性访问 在处理动态属性名的对象时可以使用索引类型来实现类型安全的属性访问。例如当从服务器返回的 JSON 数据中提取属性时可以利用索引类型来确保属性名存在并获取其对应的类型。 2.代码重用 当需要创建通用函数来操作对象属性时索引类型可以帮助我们实现更加通用和灵活的代码。例如一个通用的函数可能需要根据传入的属性名称获取属性值并进行特定的处理。 interface ServerData {id: number;name: string;age: number;// 可能还有其他动态属性
}
function getPropertyValue(obj: ServerData, key: keyof ServerData): void {console.log(obj\[key]); // 确保 obj\[key] 的类型是正确的 // 这里可以直接使用索引类型来获取属性值
}3.动态扩展对象 当需要处理来自外部来源比如 API 响应或数据库查询的动态数据时索引类型可以让我们轻松地处理这种情况而不必为每个可能的属性手动定义类型。 interface DynamicObject {[key: string]: number | string; // 允许任意属性名但属性值必须为 number 或 string 类型}
function processDynamicData(data: DynamicObject): void {for (let key in data) {console.log(key : data\[key]); // 对任意属性进行处理}
}4.类型安全性 索引类型可以增强代码的类型安全性因为它们可以捕获可能的属性名拼写错误或键不存在的情况。 5.映射类型 TypeScript 还提供了映射类型Mapped Types的概念它们利用索引类型可以根据现有类型自动生成新类型。这在创建新类型时非常有用特别是当需要在现有类型的基础上添加或修改属性时。 14. const和readonly的区别
当在TypeScript中使用const和readonly时它们的行为有一些显著的区别 const const用于声明常量值。一旦被赋值后其值将不能被重新赋值或修改。常量必须在声明时就被赋值并且该值不可改变。常量通常用于存储不会发生变化的值例如数学常数或固定的配置值。
const PI 3.14;
PI 3.14159; // Error: 无法重新分配常量readonly readonly关键字用于标记类的属性表明该属性只能在类的构造函数或声明时被赋值并且不能再次被修改。readonly属性可以在声明时或构造函数中被赋值但之后不能再被修改。readonly属性通常用于表示对象的某些属性是只读的防止外部代码修改这些属性的值。
class Person {readonly name: string;constructor(name: string) {this.name name; // 可以在构造函数中赋值}
}let person new Person(Alice);
person.name Bob; // Error: 无法分配到name因为它是只读属性总结来说const主要用于声明常量值而readonly则用于标记类的属性使其只读。
15. TypeScript 中 any 类型的作用是什么滥用会有什么后果
在TypeScript中any类型的作用是允许我们在编写代码时不指定具体的类型从而可以接受任何类型的值。使用any类型相当于放弃了对该值的静态类型检查使得代码在编译阶段不会对这些值进行类型检查。
主要情况下any类型的使用包括以下几点 当我们不确定一个变量或表达式的具体类型时可以使用any类型来暂时绕过类型检查。 在需要与动态类型的JavaScript代码交互时可以使用any类型来处理这些动态类型的值。 有时候某些操作难以明确地定义其类型或者需要较复杂的类型推导时也可以使用any类型。
滥用的后果
尽管any类型提供了灵活性但由于它会放弃TypeScript的静态类型检查因此滥用any类型可能会降低代码的健壮性和可维护性。当滥用any类型时可能会导致以下后果
1.代码可读性下降
let data: any;
// 代码中的使用方式
data.someUnknownMethod(); // 在编译阶段不会报错但实际上可能是一个错误2.潜在的运行时错误
let myVariable: any 123;
myVariable.toUpperCase(); // 在编译阶段不会报错但在运行时会引发错误3.类型安全受损
function add(x: any, y: any): any {return x y; // 编译器无法推断返回值的具体类型
}滥用any类型会导致代码失去了TypeScript强大的类型检查功能带来了如下问题
可能引入未知的运行时行为和错误。降低了代码的可维护性和可读性因为难以理解某些变量或参数的具体类型。
因此在实际开发中应尽量避免过度使用any类型。可以通过合适的类型声明、接口定义和联合类型等方式提高代码的健壮性和可维护性。
16. TypeScript中的this有什么需要注意的
在TypeScript中与JavaScript相比this的行为基本上是一致的。然而TypeScript提供了类型注解和类型检查可以帮助开发者更容易地理解和处理this关键字的使用。 在noImplicitThis为true 的情况下必须声明 this 的类型才能在函数或者对象中使用this。 Typescript中箭头函数的 this 和 ES6 中箭头函数中的 this 是一致的。 在TypeScript中当将noImplicitThis设置为true时意味着在函数或对象中使用this时必须显式声明this的类型。这一设置可以帮助开发者更明确地指定this的类型以避免因为隐式的this引用而导致的潜在问题。
具体来说如果将noImplicitThis设置为true则在下列情况下必须显式声明this的类型
在函数内部使用this时需要使用箭头函数或显示绑定this。在某些类方法或对象方法中需要明确定义this的类型。
示例代码如下所示
class MyClass {private value: number 42;public myMethod(this: MyClass) {console.log(this.value);}public myMethod2 () {console.log(this.value);}
}let obj new MyClass();
obj.myMethod(); // 此处必须传入合适的 this 类型通过将noImplicitThis设置为trueTypeScript要求我们在使用this时明确指定其类型从而在编译阶段进行更严格的类型检查帮助避免一些可能出现的错误和不确定性。
注noImplicitThis是TypeScript编译器的一个配置选项用于控制在函数或对象方法中使用this时的严格性。当将noImplicitThis设置为true时意味着必须显式声明this的类型否则会触发编译错误。
17. TypeScript数据类型
在TypeScript中常见的数据类型包括以下几种 基本类型 number: 表示数字包括整数和浮点数。string: 表示文本字符串。boolean: 表示布尔值即true或false。null、undefined: 分别表示null和undefined。symbol: 表示唯一的、不可变的值。 复合类型 array: 表示数组可以使用number[]或Arraynumber来声明其中元素的类型。tuple: 表示元组用于表示固定数量和类型的数组。enum: 表示枚举类型用于定义具名常量集合。 对象类型 object: 表示非原始类型即除number、string、boolean、symbol、null或undefined之外的类型。interface: 用于描述对象的结构并且可以重复使用。 函数类型 function: 表示函数类型。void: 表示函数没有返回值。any: 表示任意类型。 高级类型 union types: 表示一个值可以是几种类型之一。intersection types: 表示一个值同时拥有多种类型的特性。
18. interface可以给Function/Array/ClassIndexable)做声明吗
在TypeScript中interface可以用来声明函数、数组和类具有索引签名的类。下面是一些示例代码
1. Interface 声明函数
interface MyFunc {(x: number, y: number): number;
}let myAdd: MyFunc function(x, y) {return x y;
};在上述示例中MyFunc接口描述了一个函数类型该函数接受两个参数并返回一个数字。
2. Interface 声明数组
interface StringArray {[index: number]: string;
}let myArray: StringArray;
myArray [Bob, Alice];上面的示例中StringArray接口描述了一个具有数字索引签名的字符串数组。意味着我们可以通过数字索引来访问数组元素。
3. Interface 声明类Indexable
interface StringDictionary {[index: string]: string;
}let myDict: StringDictionary {name: John,age: 30
};在这个例子中StringDictionary接口用于描述具有字符串索引签名的类或对象。这使得我们可以像操作字典一样使用对象的属性。
综上TypeScript中的interface可以被用来声明函数、数组和具有索引签名的类从而帮助我们定义和限定这些数据结构的形式和行为。
19. TypeScript中的协变、逆变、双变和抗变是什么
在TypeScript中协变Covariance、逆变Contravariance、双变Bivariance和抗变Invariance 是与类型相关的概念涉及到参数类型的子类型关系。下面对这些概念进行解释并提供示例代码。
协变Covariance
区别协变意味着子类型可以赋值给父类型。应用场景数组类型是协变的因此可以将子类型的数组赋值给父类型的数组。
协变表示类型T的子类型可以赋值给类型U当且仅当T是U的子类型。在TypeScript中数组是协变的这意味着可以将子类型的数组赋值给父类型的数组。
let subtypes: string[] [hello, world];
let supertype: Object[] subtypes; // 数组是协变的这是合法的逆变Contravariance
区别逆变意味着超类型可以赋值给子类型。应用场景函数参数类型是逆变的因此可以将超类型的函数赋值给子类型的函数。
逆变表示类型T的超类型可以赋值给类型U当且仅当T是U的子类型。在TypeScript中函数参数是逆变的这意味着可以将超类型的函数赋值给子类型的函数。
type LoggerT (arg: T) void;
let logNumber: Loggernumber (x: number) console.log(x);
let logAny: Loggerany logNumber; // 函数参数是逆变的这是合法的双变Bivariance
区别双变允许参数类型既是协变又是逆变的。应用场景对象类型是双变的这意味着可以将子类型的对象赋值给父类型的对象同时也可以将超类型的对象赋值给子类型的对象。
双变允许参数类型既是协变又是逆变的。在TypeScript中普通对象类型是双变的这意味着可以将子类型的对象赋值给父类型的对象并且可以将超类型的对象赋值给子类型的对象。
interface Animal {name: string;
}interface Dog extends Animal {breed: string;
}let animal: Animal { name: Animal };
let dog: Dog { name: Dog, breed: Labrador };animal dog; // 对象类型是双变的这是合法的
dog animal; // 对象类型是双变的这也是合法的抗变Invariance
区别抗变表示不允许类型之间的任何赋值关系。应用场景通常情况下基本类型和类类型是抗变的。
抗变表示不允许类型T和U之间的任何赋值关系即T既不是U的子类型也不是U的超类型。在TypeScript中一般情况下基本类型和类类型是抗变的。
let x: string hello;
let y: string x; // 这是合法的let a: Animal { name: Animal };
let b: Animal a; // 这也是合法的20. TypeScript中的静态类型和动态类型有什么区别
静态类型是在 编译期间 进行类型检查可以在编辑器或 IDE 中发现大部分类型错误。动态类型是在 运行时 才确定变量的类型通常与动态语言相关联。
静态类型Static Typing
定义静态类型是指在编译阶段进行类型检查的类型系统通过类型注解或推断来确定变量、参数和返回值的类型。特点静态类型能够在编码阶段就发现大部分类型错误提供了更好的代码健壮性和可维护性。优势可以在编辑器或 IDE 中实现代码提示、自动补全和类型检查帮助开发者减少错误并提高代码质量。
动态类型Dynamic Typing
定义动态类型是指在运行时才确定变量的类型通常与动态语言相关联允许同一个变量在不同时间引用不同类型的值。特点动态类型使得变量的类型灵活多变在运行时可以根据上下文或条件动态地改变变量的类型。优势动态类型可以带来更大的灵活性适用于一些需要频繁变化类型的场景。
区别总结
时机差异静态类型在编译期间进行类型检查而动态类型是在运行时才确定变量的类型。代码稳定性静态类型有助于在编码阶段发现大部分类型错误提高代码稳定性动态类型对类型的要求较为灵活但可能增加了代码的不确定性。使用场景静态类型适合于大型项目和团队能够提供更强的类型安全性动态类型适用于快速原型开发和灵活多变的场景能够更快地迭代和测试代码。
21. 介绍TypeScript中的可选属性、只读属性和类型断言
可选属性 使用 ? 来标记一个属性可以存在也可以不存在。只读属性 使用 readonly 关键字来标记一个属性是只读的。类型断言 允许将一个实体强制指定为特定的类型使用 Type 或 value as Type。
代码示例
// 可选属性
interface Person {name: string;age?: number; // 可选属性
}// 只读属性
interface Point {readonly x: number;readonly y: number;
}
let p1: Point { x: 10, y: 20 };
p1.x 5; // Error: 只读属性无法重新赋值// 类型断言
let someValue: any hello;
let strLength: number (someValue as string).length;22. TypeScript 中的模块化是如何工作的举例说明
答案
TypeScript 中使用 ES6 模块系统可以使用 import 和 export 关键字来导入和导出模块。可以通过 export default 导出默认模块在导入时可以使用 import moduleName from modulePath。
代码示例
// math.ts
export function sum(a: number, b: number): number {return a b;
}
export function subtract(a: number, b: number): number {return a - b;
}// app.ts
import { sum, subtract } from ./math;
console.log(sum(3, 5)); // 输出 8结尾
本文整理了一些ts的常见面试问题希望对你的理解有所帮助。
❤️ 未来也会继续更新文章欢迎围观如有不足与错误也欢迎指正 如果这篇文章对您有帮助麻烦 点赞、收藏 关注与我一起成长❤️