JavaScript (JS) 和 TypeScript (TS) 。
JavaScript (JS):Web 的基石
-
核心地位: JavaScript 是互联网的“官方”脚本语言。几乎所有现代浏览器都原生支持它,Node.js 让它也能在服务器端运行。它是构建交互式网页和绝大多数 Web 应用的基础。
-
动态类型 (Dynamic Typing): 这是 JS 最显著的特点之一。你不需要在声明变量时指定它的类型(比如是数字、字符串还是布尔值)。变量的类型是在程序运行时根据赋给它的值确定的,并且可以随时改变。
let message = "Hello"; // message 是字符串 message = 123; // 现在 message 变成数字了,JS 允许这样做
-
灵活性高: 动态类型带来了极大的灵活性。写起来很快,对初学者友好,适合快速原型开发和小项目。
-
运行时错误: 灵活性的代价是,很多类型相关的错误(比如你以为一个变量是数字,但它其实是 undefined,然后你尝试对它做数学运算)只有在代码实际运行到那一行时才会被发现。这可能导致调试困难,尤其是在大型复杂项目中。
-
解释执行(通常): 虽然现代 JS 引擎(如 V8)有复杂的即时编译 (JIT) 过程,但从开发者的角度看,JS 代码通常不需要显式的编译步骤就能直接在环境中运行。
-
生态庞大: 拥有世界上最大的开源包生态系统 (npm),无数的框架、库和工具可供使用。
TypeScript (TS):JS 的超集和严谨的建筑师
-
超集关系 (Superset): 这是理解 TS 的关键。TypeScript 包含了 JavaScript 的所有功能,并添加了新的特性,最核心的就是静态类型系统。任何有效的 JavaScript 代码基本上也是有效的 TypeScript 代码(可能有极少数边缘情况例外)。你可以把 TS 想象成 "带类型的 JavaScript"。
-
静态类型 (Static Typing): 这是 TS 的核心价值所在。你可以在声明变量、函数参数、函数返回值时明确指定类型。
let message: string = "Hello"; // 明确 message 是字符串类型 // message = 123; // 编译错误!不能将数字赋值给字符串类型的变量 function greet(name: string): string { // 参数和返回值都有类型 return "Hello, " + name; }
-
编译时错误检查: TypeScript 代码需要通过编译器 (tsc) 转换成普通的 JavaScript 代码才能运行。在这个编译阶段,TS 会进行严格的类型检查。如果发现类型不匹配(比如把数字传给了需要字符串的函数),编译器会报错,让你在开发阶段就能发现并修复问题,而不是等到运行时。这就像写代码时旁边有个语法和类型拼写检查器。
-
更好的工具支持: 静态类型极大地增强了代码编辑器的能力,比如更精准的自动补全 (IntelliSense)、代码导航、重构等。这对于大型项目和团队协作非常有帮助。
-
代码可读性和可维护性: 类型注解就像代码的文档,让其他人(或者未来的你)更容易理解代码的意图和数据结构,降低了维护成本。
-
引入额外特性: 除了类型系统,TS 还引入或更早支持了一些 ECMAScript 的新特性(最终也会成为 JS 的标准),以及它自己独有的特性,如接口 (Interfaces)、枚举 (Enums)、泛型 (Generics)、访问修饰符 (public/private/protected) 等,这些有助于编写更健壮、更结构化的面向对象代码。
-
需要编译步骤: 使用 TS 意味着你的开发流程中多了一个编译步骤,将 .ts 文件转换为 .js 文件。
总结我的理解:
- JS 是基础,是终点。 所有 TS 代码最终都要变成 JS 才能运行。JS 灵活、快速、普及度极高,适用于各种规模的项目,但大型项目中维护性可能面临挑战。
- TS 是 JS 的增强,是开发时的“安全网”和“加速器”。 它通过引入静态类型,把很多可能在运行时发生的错误提前暴露在开发阶段,提高了代码的健壮性、可维护性,并改善了开发体验(尤其是在大型项目和团队协作中)。它不是要取代 JS,而是提供一种更结构化、更安全的方式来编写 JS 应用。
选择哪个?
- 小型项目、快速原型、个人脚本: JS 可能足够,写起来更快。
- 中大型项目、团队协作、需要长期维护的应用、库/框架开发: TS 的优势(类型安全、工具支持、可维护性)通常会超过它带来的额外学习成本和编译步骤。
ts的数据类型有哪些
- 基础数据类型
string number boolean null undefined symbol bigInt
- ts特有的类型
any never unknow void tuple enum
- 对象类型
object array type interface
- 组合类型
联合类型 交叉类型
- 其他
字面量类型 函数类型
1. JavaScript 基础类型 (Primitives)
这些是 JavaScript 就有的基本类型,TypeScript 完全支持,并可以进行类型注解:
-
string:表示文本数据(字符串)。
let name: string = "Alice";
-
number:表示数字,包括整数和浮点数。
let age: number = 30; let price: number = 99.9;
-
boolean:表示布尔值(true 或 false)。
let isActive: boolean = true;
-
null:表示一个有意的“空”或“无”的值。 (本身也是一个类型)
let data: null = null;
-
undefined:表示一个未定义或未初始化的值。(本身也是一个类型)
let notAssigned: undefined = undefined; let declaredButNotSet: string; // 默认值是 undefined
-
symbol (ES6 新增):表示全局唯一的引用值,常用于对象属性的键。
let sym: symbol = Symbol("key");
-
bigint (ES2020 新增):表示任意精度的整数,用于处理超出 number 类型安全整数范围的大整数。
let bigNum: bigint = 100n;
2. TypeScript 特有类型
这些是 TypeScript 为了增强类型系统而添加的:
-
any:表示任意类型。使用 any 会放弃类型检查,允许你像在普通 JavaScript 中一样操作变量。应谨慎使用,因为它会削弱 TypeScript 的类型安全优势。
let flexible: any = 4; flexible = "Now I'm a string"; flexible = false; // 不会报错
-
unknown:表示未知类型。它是 any 的类型安全版本。你可以将任何类型的值赋给 unknown,但在对 unknown 类型的值执行操作之前,必须先进行类型检查或类型断言来缩小范围。
let maybe: unknown; maybe = 10; maybe = "hello"; // let len: number = maybe.length; // 编译错误!不能直接操作 unknown 类型 if (typeof maybe === 'string') { let len: number = maybe.length; // OK,类型检查后可以安全使用 }
-
void:表示没有任何类型。通常用于标记函数没有返回值。
function logMessage(message: string): void { console.log(message); // 没有 return 语句,或者 return; } // 也可以声明 void 类型的变量,但意义不大,通常只能赋值 undefined 或 null(取决于编译选项) let unusable: void = undefined;
-
never:表示永远不会存在的值的类型。常用于:
- 抛出异常或无限循环的函数的返回值类型。
- 在类型保护中,表示不可能发生的逻辑分支。
function error(message: string): never { throw new Error(message); } function infiniteLoop(): never { while (true) {} }
-
tuple (元组) :表示一个固定数量和固定类型的元素数组。数组中每个位置的类型都已确定。
let person: [string, number] = ["Alice", 30]; // person[0] 必须是 string, person[1] 必须是 number // person[2] = true; // 编译错误!元组长度固定 // person[0] = 100; // 编译错误!第一个元素必须是 string
-
enum (枚举) :用于定义一组带名字的常量(数值或字符串)。
// 数字枚举(默认从 0 开始) enum Color { Red, Green, Blue } let c: Color = Color.Green; // c 的值是 1 // 字符串枚举 enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT" } let dir: Direction = Direction.Up; // dir 的值是 "UP"
3. 对象类型 (Object Types)
除了基本类型,你还可以定义更复杂的结构:
-
array:表示数组。有两种写法:
let list1: number[] = [1, 2, 3]; let list2: Array<string> = ["a", "b", "c"];
-
object:表示非原始类型(即不是 string, number, boolean, symbol, null, undefined, bigint 的类型)。通常我们不直接用 object,而是定义更具体的对象结构。
-
接口 (interface) :用于定义对象的“形状”(包含哪些属性,以及这些属性的类型)。
interface User { name: string; age: number; isAdmin?: boolean; // 可选属性 readonly id: number; // 只读属性 } let user: User = { name: "Bob", age: 25, id: 1 };
-
类型别名 (type) :可以为任何类型(包括基本类型、联合类型、元组、对象结构等)创建一个新的名字。
type Point = { x: number; y: number; }; let p: Point = { x: 10, y: 20 }; type ID = string | number; // 联合类型别名 let userId: ID = "abc-123"; userId = 456;
4. 组合类型 (Combination Types)
-
联合类型 (|) :表示一个值可以是几种类型之一。
let id: string | number; id = 101; id = "abc"; // id = true; // 编译错误
-
交叉类型 (&) :表示一个值必须同时满足多种类型的特征。常用于合并接口类型。
type Person = { name: string }; type Worker = { job: string }; type WorkingPerson = Person & Worker; const p: WorkingPerson = { name: "Alice", job: "Engineer" };
5. 其他
-
字面量类型 (Literal Types) :允许你指定变量必须是某个具体的字符串、数字或布尔值。
let alignment: 'left' | 'center' | 'right'; alignment = 'center'; // alignment = 'top'; // 编译错误
-
函数类型 (Function Types) :定义函数的参数类型和返回值类型。
type AddFunc = (x: number, y: number) => number; let add: AddFunc = (a, b) => a + b;
any unknow never 的区别
特性 | any | unknown | never |
---|---|---|---|
含义 | 放弃类型检查 | 未知类型,需检查后使用 | 永不存在的值 |
类型安全 | 低 | 高 | N/A (代表不可能) |
赋给它? | 任何值都可以 | 任何值都可以 | 没有任何值可以 (除 never) |
赋给其他? | 可以赋给任何类型 (危险!) | 只能赋给 any 或 unknown (除非检查/断言) | 可以赋给任何类型 (无意义) |
直接操作? | 可以 (危险!) | 不可以 (除非检查/断言) | N/A (无值可操作) |
主要用途 | JS 迁移 (临时), 应避免 | 类型安全的 any 替代品 | 不返回函数, 穷尽检查 |
简单来说:
- 用 any 就是跟 TypeScript 说“别烦我”。
- 用 unknown 就是跟 TypeScript 说“我不知道这是啥,帮我看着点,等我搞清楚了再用”。
- 用 never 就是跟 TypeScript 说“这地方代码根本执行不到”或者“这个函数压根就不会正常结束”。
ts中基本类型的大小写区别
原始类型(推荐使用 ✅) | 包装对象类型(不推荐 ❌) | 说明 |
---|---|---|
string | String | 字符串 |
number | Number | 数值 |
boolean | Boolean | 布尔值 |
symbol | Symbol | ES6 的 symbol |
bigint | BigInt | ES2020 的大整数类型 |
string vs String
-
它表示的是 JavaScript 中的基本字符串类型(primitive string)。
-
是我们在大多数场景中应该使用的类型。
-
示例:
let a: string = "hello";
-
它其实是 JavaScript 中的一个构造函数类型:
const b = new String("hello"); // 这是一个 String 对象
-
这种写法通常不推荐使用,因为它是一个对象而不是基本类型。
number vs Number
-
number (小写): 代表原始的数字类型(包括整数和浮点数)。这是进行类型注解时应使用的关键字。
let age: number = 30; let price: number = 19.99;
-
Number (大写): 指的是 JavaScript 内置的 Number 构造函数,或通过 new Number() 创建的 Number 对象实例。不推荐用作类型注解。
let numObj: Number = new Number(100); // 不推荐 console.log(typeof age); // "number" console.log(typeof numObj); // "object"
boolean vs Boolean
-
boolean (小写): 代表原始的布尔类型(true 或 false)。这是进行类型注解时应使用的关键字。
let isActive: boolean = true;
-
Boolean (大写): 指的是 JavaScript 内置的 Boolean 构造函数,或通过 new Boolean() 创建的 Boolean 对象实例。不推荐用作类型注解。
let boolObj: Boolean = new Boolean(false); // 不推荐 console.log(typeof isActive); // "boolean" console.log(typeof boolObj); // "object"
symbol vs Symbol
-
symbol (小写): 代表 ES6 引入的原始符号类型。这是进行类型注解时应使用的关键字。
let id: symbol = Symbol("uniqueId");
-
Symbol (大写): 指的是 JavaScript 内置的 Symbol 构造函数。注意:你不能使用 new Symbol(),而应该直接调用 Symbol() 来创建符号。类型注解时仍应使用小写的 symbol。
let symConstructor = Symbol; // 获取构造函数本身 let anotherId = Symbol("key"); console.log(typeof id); // "symbol"
bigint vs BigInt
-
bigint (小写): 代表 ES2020 引入的任意精度整数类型。这是进行类型注解时应使用的关键字。
let bigNum: bigint = 12345678901234567890n;
-
BigInt (大写): 指的是 JavaScript 内置的 BigInt 构造函数。注意:你不能使用 new BigInt(),而应该直接调用 BigInt() 来创建大整数。类型注解时仍应使用小写的 bigint。
let bigIntConstructor = BigInt; // 获取构造函数本身 let anotherBigNum = BigInt("98765432109876543210"); console.log(typeof bigNum); // "bigint"
还有一个特殊但重要的对比:
object vs Object
-
object (小写): 这是 TypeScript 引入的一个类型,代表所有非原始类型(即不是 string, number, boolean, symbol, bigint, null, undefined 的任何类型)。它比 Object 更具体一些,但通常不如使用接口 (interface) 或具体的类型别名 (type) 来描述对象结构有用。
let obj: object; obj = { name: "Alice" }; obj = [1, 2, 3]; obj = () => {}; // obj = "hello"; // 错误,string 是原始类型 // obj = 42; // 错误,number 是原始类型 // obj = null; // 错误 (除非编译选项允许) // obj = undefined; // 错误 (除非编译选项允许)
-
Object (大写): 指的是 JavaScript 的内置 Object 构造函数或其创建的实例类型。它几乎代表了 JavaScript 中的所有值(除了 null 和 undefined,取决于严格性设置)。使用 Object 作为类型注解通常过于宽泛,失去了类型检查的很多意义,强烈不推荐。 {} 或 Record<string, any> (或更具体的 Record<string, unknown>) 通常是更好的替代品,但定义明确的接口或类型别名是最佳选择。
let anyObject: Object = { a: 1 }; // 不推荐 anyObject = "hello"; // 可能会工作,但非常不好
对于所有 JavaScript 的原始数据类型 (string, number, boolean, symbol, bigint),在 TypeScript 中进行类型注解时,始终使用它们对应的小写关键字形式。
避免使用大写的 String, Number, Boolean, Symbol, BigInt 以及 Object 作为类型注解,因为它们通常指向构造函数或对象包装器,这会降低代码清晰度并可能引入潜在的错误。对于对象类型,优先使用 interface 或 type 来定义具体的结构。