1.什么是TS?
TypeScript 是一种开源的编程语言,它是 JavaScript 的一个超集,添加了静态类型检查和其他一些特性。TypeScript 提供了更强大的静态类型系统,有助于编写更可靠和可维护的 JavaScript 代码。
2.项目中为什么要使用TS
在项目中使用 TypeScript (TS) 有一些好处,下面是其中一些常见的好处:
- 强大的静态类型检查:TypeScript 提供了静态类型系统,允许在编码阶段检测出潜在的类型错误和逻辑错误。这可以帮助开发者在开发过程中捕获和修复错误,减少在运行时出现的错误。类型检查还可以提供更好的代码提示和自动完成功能,提高代码的可读性和可维护性。
- 更好的代码组织和可维护性:TypeScript 支持模块化和面向对象的编程,可以帮助开发者更好地组织和管理代码。通过使用接口、类、命名空间等特性,可以提高代码的可读性、可维护性和可扩展性。
- 更好的开发工具支持:TypeScript 提供了丰富的开发工具支持,包括代码编辑器(如Visual Studio Code)、静态分析工具和调试器等。开发者可以受益于强大的工具集,使开发过程更高效、更准确。
- 渐进式采用:TypeScript 兼容 JavaScript,可以将现有的 JavaScript 代码渐进式地迁移到 TypeScript。这意味着可以逐步引入 TypeScript,无需一次性重写整个代码库,从而降低了迁移成本。
- 社区和生态系统支持:TypeScript 是一个活跃的开源项目,有庞大的社区和生态系统支持。有大量的第三方库和工具可用于 TypeScript,并且有许多优秀的 TypeScript 资源和学习资料可供参考。
3.说说你知道的ts中的数据类型
ts是js的超集,所以js的数据类型ts都支持
js中的基础数据类型:Number,String,Null,Undefined,Boolean,Symbol...
js中的引用数据类型:Function,Array,Object...
此外ts还有自己特有的数据类型:
enum 枚举 any 任意
generic 泛型 tuple 元组
unknown 未知 void 没有返回值
never 从不出现 ...
4.你了解any类型吗,谈谈你对他的理解,一般any你会用在什么场景下
了解,当我们在 TypeScript 中声明变量或函数参数的类型时,有时候无法确定其具体的类型,或者希望允许任何类型的赋值。这时可以使用 “any” 类型来表示这种不确定或任意类型。
场景:
- 类型转换不确定的情况:在某些情况下,我们无法确定一个值的具体类型,或者希望将一个变量用于多种类型。这时可以使用 “any” 类型来暂时接受任意类型,并进行相应的类型转换或处理。
- 动态数据的处理:当处理来自外部或动态数据源的数据时,我们通常无法提前知道数据的具体类型。在这种情况下,可以使用 “any” 类型来容纳任意类型的数据,并在运行时进行相应的类型检查和处理。
5.unknown和any有什么区别
在 TypeScript 中,“unknown” 和 “any” 是两种表示不确定类型的机制,但它们有一些关键区别。
-
类型安全性:- “unknown”: 当一个值的类型被声明为 “unknown” 时,它是一个类型安全的容器。这意味着你不能直接对 “unknown” 类型的值进行操作,除非你显式地进行类型检查或类型断言,将其转换为其他已知的类型。这可以提供更强的类型安全性,因为它阻止你在不明确类型的情况下进行随意的操作。
- “any”: 当一个值的类型被声明为 “any” 时,它是类型不安全的,可以接受任何类型的赋值,并且可以随意进行操作,而不会引发类型检查或编译错误。这样的灵活性可能会在某些情况下带来方便,但也降低了类型安全性。
-
类型推断与类型信息:- “unknown”: TypeScript 对 “unknown” 类型的值具有更严格的推断规则。当你执行对 “unknown” 类型的操作时,通常需要进行类型检查或类型断言,以便 TypeScript 可以推断出具体的类型信息。这有助于处理类型不确定的情况,并鼓励对类型进行明确的处理。
- “any”: 当一个值的类型被声明为 “any” 时,TypeScript 将对其进行最小化的类型检查,并且对它进行的操作不会对类型系统产生影响。TypeScript 不会提供关于该值的具体类型信息,也不会进行类型推断。
-
类型约束:- “unknown”: 当一个值的类型被声明为 “unknown” 时,它在被赋值给其他变量或作为函数参数传递时,会强制进行类型检查或类型断言。这确保了类型的一致性和明确性。
- “any”: 当一个值的类型被声明为 “any” 时,它可以被赋值给任何类型的变量,并且可以传递给任何函数参数,而不会强制进行类型检查。这允许了更大的灵活性,但也丧失了一些类型约束和类型安全性。
综上所述,“unknown” 和 “any” 都可以用来表示不确定类型,但它们在类型安全性、类型推断与信息和类型约束等方面存在差异。建议在编写 TypeScript 代码时,尽量避免使用 “any”,而是使用更具体的类型或将类型不确定的值声明为 “unknown” 来提高代码的类型安全性和可维护性。
6.3. never表示什么,unknown表示什么,分别用在什么场景下。
never: 永远不可能出现值 unknown: 有多种可能性,但是具体哪一种不知道
场景: never -> 函数中最终的结果是抛出一个错误,这个时候就可以把函数的返回值标注成never unknown -> 类型断言的时候,需要用unknown做中转
7.interface 和 type的去区别
在 TypeScript 中,interface 和 type 都用于定义自定义类型,但它们有一些关键区别。
主要区别如下:
-
语法差异:
interface:使用interface关键字定义接口,可以在接口中声明属性、方法等。例如:interface Person { name: string; age: number; }type:使用type关键字定义类型别名,可以给现有的类型起一个新的名字。例如:type Person = { name: string; age: number; };
-
扩展性差异:
interface:支持扩展其他接口,使用extends关键字实现接口之间的继承。例如:interface Employee extends Person { salary: number; }type:支持联合类型、交叉类型和元组等高级类型的定义,可以使用泛型进行更复杂的类型操作。例如:type Name = string | null;或type Point = { x: number; y: number; } & { color: string; }
-
同名合并行为:
interface:可以多次声明同一个名字的接口,并且它们会自动合并为一个接口。例如:interface Person { name: string; } interface Person { age: number; }type:不能直接多次声明同一个名字的类型别名,因为它们会覆盖原来的定义。
-
可读性差异:
interface:常用于定义对象的形状,更符合直觉,可读性更好,因为它定义了一种新的类型。type:更灵活,可以给现有类型起别名,以便引用或复用。可以用于定义复杂的类型。
根据需求的不同,选择使用 interface 还是 type 取决于你的具体场景和个人偏好。通常,使用 interface 来描述对象和类的形状,使用 type 来定义更复杂的类型别名、联合类型或交叉类型。在项目中,你也可以同时使用它们,根据具体情况进行选择。
8.什么是字面量类型数据,什么场景下会出现字面量数据
字面量类型是指将具体的字面值作为类型的一部分。它允许我们将值限定为特定的字面量,而不仅仅是某个类型的子集。
在 TypeScript 中,我们可以使用字面量类型来表示一个具体的值。
当我们给一个变量设置值的时候可以使用字面量类型,使这个数据只能存放字面量数据的某一个子集
type Gender = "man" | "woman"
const genser: Gender = "man"; // 只能是 "man", "woman" 之一
9.TS中如何使用类型断言,一般使用在什么场景下,需要注意什么?
开发者清楚数据的类型,但是ts无法理解,可以强制告诉ts编译器,当前数据是什么类型.
场景: 一个变量存在多种类型的可能性,但是实际在传递值的时候可能只有一种.
注意: ts中无法直接把一种类型断言为另外一种类型,中间需要unknown做中转.
10.TS在类中支持的类中的修饰符有哪些,分别有什么特点。
- public 公开的,可以在任何位置使用属性
- protected 受保护的, 使用了该修饰符的属性或者方法只能在类本身和子类中使用
- private 私有的, 只能在自身的类中使用
11.简单聊聊你对TS中的枚举类型数据的理解
enum 中的常量在不赋值的情况会自动进行分配值,值从0开始,逐步递增
enum Direction {
Up,
Down,
Left,
Right
}
let myDirection: Direction = Direction.Up;
在上面的示例中,我们定义了一个名为 Direction 的枚举类型,并指定了一组常量值。默认情况下,这些常量值从0开始依次递增,所以Up的值为0,Down的值为1,以此类推。
然后,我们声明了一个变量 myDirection 并将其类型设置为 Direction。我们可以将枚举类型的值分配给变量,例如 Direction.Up。
如果这么设置的话:
enum Direction {
Up=1
Down,
Left=10
Right
}
那么
Up的值为 1Down的值为 2Left的值为 10Right的值为 11
12.谈谈你对TS中的泛型的理解
在 TypeScript 中,泛型(Generics)是一种特性,它允许我们在定义函数、类或接口时使用参数化类型。
简单来说就是: 动态类型标注,将标注的类型决定权给使用者。
泛型的主要用途是增强代码的可重用性、类型安全性和灵活性。下面是一些泛型的用途和好处:
- 类型安全性:使用泛型可以在编译时提供类型检查和类型推断,避免运行时的类型错误。
- 代码重用:使用泛型,我们可以编写一次具有通用类型的代码,然后在不同的上下文中重复使用它。这样可以减少重复代码的量,并且提高代码的可维护性。
- 灵活性:泛型使代码更加灵活,因为它们可以与不同类型的数据一起使用。我们可以构建适应不同数据类型的通用函数或类。
- 抽象数据类型:泛型可以用于创建抽象数据类型,使代码更具扩展性和可定制性。这样的数据类型可以根据实际需求进行类型参数化。
- 函数的泛型:通过在函数签名中使用泛型,我们可以在调用函数时指定函数参数和返回值的类型,在编译时进行类型检查,并使函数更加灵活和通用。
13.解释一下什么是类型推断和类型断言
当我们在 TypeScript 中声明变量时,可以通过两种方式来确定变量的类型:自动类型推断和类型断言。
自动类型推断(Type Inference)是 TypeScript 编译器根据代码上下文自动推断出变量的类型,而无需显式指定类型。TypeScript 根据变量的赋值表达式、函数返回值等进行推断。
下面是一个示例:
let foo = 42; // foo 推断为 number 类型
let bar = "hello"; // bar 推断为 string 类型
let baz = true; // baz 推断为 boolean 类型
在上述示例中,变量的类型是根据其初始值的类型自动推断出来的。这减少了手动指定类型的冗余,并且在代码编写时提供了一定的类型安全性。
类型断言(Type Assertion)也被称为类型转换。它允许开发者手动指定变量的类型,即使 TypeScript 的类型推断机制可能得出不同的类型。通过类型断言,我们可以告诉编译器我们比它更了解变量的类型。
类型断言有两种形式:
- 使用尖括号(
<类型>)语法:
let value: any = "hello";
let length: number = (<string>value).length;
在这个例子中,我们告诉编译器变量 value 是一个 any 类型,但我们确切知道它是一个字符串。通过类型断言 <string>,我们可以访问字符串类型的 length 属性。
- 使用 “as” 关键字:
let value: any = "hello";
let length: number = (value as string).length;
这种方式与尖括号语法相同,只是使用了 as 关键字进行类型断言。
需要注意的是,类型断言并不会进行类型转换或运行时的类型检查,它只是在编译时告诉编译器使用指定的类型。
14.现有一个JS项目,你该如何把JS项目升级为TS项目,你有什么想法。
- 初始化 TypeScript 项目:通过在项目根目录中运行
npm init命令初始化一个新的 TypeScript 项目。这将创建一个package.json文件来管理项目依赖和配置。 - 安装 TypeScript:使用
npm install typescript --save-dev命令安装 TypeScript 作为项目的开发依赖。 - 创建 tsconfig.json 文件:在项目根目录创建一个名为
tsconfig.json的文件来配置 TypeScript 项目。可以手动创建或运行npx tsc --init命令自动生成该文件,并根据需要进行适当的配置。例如,可以指定输出目录、启用的编译选项等。 - 重命名 JavaScript 文件为 TypeScript 文件:将 JavaScript 文件的扩展名从
.js改为.ts或.tsx(如果使用 JSX)。 - 逐步迁移:根据项目规模和复杂性,可以逐步将 JavaScript 文件中的代码转换为 TypeScript。可以从顶层开始,一次转换一个文件,然后检查编译器报告的错误,并逐步修复这些错误。
- 类型注解和类型定义:为代码添加类型注解,这是 TypeScript 的主要特性之一。通过为变量、函数参数、返回值等添加类型注解,可以提供更好的类型安全性和代码理解性。
- 类型定义文件:如果项目依赖于第三方 JavaScript 库,需要为这些库编写或找到相应的类型定义文件(
.d.ts文件),以便在 TypeScript 项目中正确引用和使用这些库。 - 编译 TypeScript 代码:使用 TypeScript 编译器(TSC)编译 TypeScript 代码。可以在终端中运行
npx tsc命令来编译项目。根据tsconfig.json中的配置,编译后的 JavaScript 文件将输出到指定的目录中。 - 解决编译错误:在编译 TypeScript 代码时,可能会遇到一些错误和警告。根据编译器的报告,解决这些错误和警告,并确保项目能够成功编译。
- 测试和调试:在项目升级完成后,进行测试和调试,确保功能的正确性和稳定性。
15.谈谈你对ts中的装饰器的理解
在 TypeScript 中,装饰器(Decorators)是一种特殊的语法,用于修改类、方法、属性或参数的行为。装饰器可以在不修改源代码的情况下,通过在它们上方应用装饰器来扩展或修改它们的功能。
装饰器使用 @ 符号紧跟在要修饰的目标之前,并可以接受一些参数。装饰器可以应用于类、类的属性、类的方法以及方法的参数上。
其中装饰器分为类装饰器 方法装饰器 属性装饰器 参数装饰器
16.declare关键字有什么作用?
在TypeScript中,declare关键字用于声明一个全局变量、函数、对象或模块的类型,告诉编译器这些实体已经存在,不需要进行编译时的检查。
declare关键字通常用于与JavaScript代码进行整合,特别是在引入第三方库或外部模块时,因为这些库的类型定义可能不存在或不完善。
通过使用declare关键字,可以提供对外部实体的类型声明,以便在编译时避免类型错误,并且可以获得代码编辑器的智能提示和自动补全功能。
以下是一些使用declare关键字的示例:
- 全局变量声明:
declare const myGlobalVar: string;
- 函数声明:
declare function myFunction(arg1: number, arg2: string): boolean;
- 对象声明:
declare namespace myNamespace {
const myProperty: number;
function myMethod(): void;
}
- 模块声明:
declare module 'myModule' {
export function myFunction(): void;
}
请注意,使用declare关键字只会在类型层面上提供声明,并不会在运行时创建变量或函数。因此,确保在使用declare声明外部实体时,确实存在该实体的实现或库文件。