基础类型
关于数组
1. 我想声明一个number组成的数组,可以声明的方式如下
简单类型
优先使用 number[]
,因为它更简洁,社区更常见
//一维数组
let list: number[] = [1, 2, 3];
//二维数组
let list: number[][] = [1, 2, 3];
// 元组
let list: [number, number, number] = [1, 2, 3];
复杂类型
在需要明确泛型或复杂类型时,可以使用 Array<T>
//泛型
let list: Array<number> = [1, 2, 3];
let matrix: Array<Array<number>> = [[1, 2], [3, 4]]; // 二维数组
let mixed: Array<number | string> = [1, "two", 3]; // 联合类型数组
关于枚举
1. 先说一个场景:enum Color {Red = 1, Green, Blue} let c: Color = Color.Green;
打印c会得到什么?
deepseek解答:
这是一个很好的问题!虽然 Color.Green
的值确实是 2
(一个数字),但 TypeScript 推荐将变量 c
声明为 Color
类型(枚举类型)而不是 number
,原因如下:
1.1 语义化更强,提高代码可读性
Color
类型 明确表示c
只能是Color.Red
、Color.Green
或Color.Blue
,而不是任意数字。- 如果声明为
number
,c
可以被赋值为4
、5
或任何数字,但逻辑上它应该只代表Color
的枚举值。
示例对比:
// ✅ 正确:c 只能是 Color 的成员
let c: Color = Color.Green; // 只能 = Color.Red / Color.Green / Color.Blue
// ❌ 不推荐:c 可以是任意数字,失去类型约束
let c: number = Color.Green;
c = 100; // 逻辑错误,但 TypeScript 不会报错
1.2 类型安全,避免无效值
- 如果
c
是Color
类型,尝试赋值非法值会触发 TypeScript 错误:let c: Color = Color.Green; c = 99; // ❌ TS 报错:不能将 99 分配给类型 Color
- 如果
c
是number
,则无法检测这种逻辑错误:let c: number = Color.Green; c = 99; // ✅ TS 不报错,但逻辑错误(99 不是有效的 Color)
1.3 便于代码维护和重构
- 如果未来
Color
的取值变化(例如Green
从2
改为3
),只需修改enum
定义,所有用到Color
类型的地方会自动适应。 - 如果直接使用
number
,你需要手动检查所有用到2
的地方是否应该改为3
,容易出错。
1.4 编辑器智能提示(Autocomplete)
- 声明为
Color
类型时,编辑器(如 VS Code)会提供枚举成员的自动补全:let c: Color = Color. // 输入时会提示 Red、Green、Blue
- 如果声明为
number
,则无法获得这种提示。
1.5 运行时仍可反向映射(数字枚举的特性)
虽然 c
的值是 2
,但数字枚举允许反向查找名称:
console.log(Color[c]); // 输出 "Green"(如果 c = 2)
如果 c
是 number
类型,这种反向映射会失去关联性。
什么时候应该用 number
代替 Color
?
极少数情况下,如果你确实需要 c
接受任意数字(而不仅仅是枚举值),才声明为 number
。但这种情况通常意味着设计有问题,应该优先考虑使用枚举。
总结
let c: Color
:表示c
是Color
枚举的成员,类型更严格,代码更安全、可读。let c: number
:失去语义约束,允许任意数字,不推荐。
TypeScript 的枚举本质上是编译时类型 + 运行时对象,既提供类型检查,又保留实际的 JavaScript 值(这里是数字 2
),所以最佳实践是声明为枚举类型。
关于断言
1. 一个any
类型的变量,使用时如果不使用类型断言(<string>someValue
),直接写 someValue.length
也能正常运行,为什么还要加断言?(deepseek解答)
问题分析
你提供的代码片段:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
问题:如果不使用类型断言(<string>someValue
),直接写 someValue.length
也能正常运行,为什么还要加断言?
1.1 不加断言的情况
如果直接写:
let strLength: number = someValue.length; // 不报错,能运行
- 可以运行:因为
someValue
是any
类型,TypeScript 不会对其做任何类型检查。 - 风险:如果
someValue
不是字符串(比如是number
),访问.length
会导致运行时错误(如undefined
或报错)。
1.2 加断言的好处
(1) 明确类型意图
let strLength: number = (<string>someValue).length;
- 显式告诉编译器:“我确定
someValue
是string
,请按字符串类型处理”。 - 即使
someValue
是any
,断言会强制类型检查,避免后续误操作。
(2) 提供编译时类型安全
如果 someValue
可能不是字符串,断言会帮助提前发现问题:
let someValue: any = 123; // 不是字符串
let strLength: number = (<string>someValue).length; // ❌ 编译时不会报错,但运行时报错!
虽然运行时仍可能出错,但断言是一种开发者主动承诺的标记,提醒你确保逻辑正确。
(3) 配合 --strictNullChecks
更安全
如果开启严格模式,断言可以排除 null
/undefined
:
let someValue: string | null = getStringOrNull(); // 可能返回 null
let strLength: number = (<string>someValue).length; // ❌ 不安全,可能运行时报错
let safeLength: number = someValue!.length; // ✅ 非空断言(需确保不为 null)
1.3 更推荐的方式:类型守卫
断言是“强制告诉编译器”,而类型守卫是“让编译器智能推断”:
if (typeof someValue === "string") {
let strLength: number = someValue.length; // 安全,编译器知道是 string
}
- 优势:运行时安全,无需手动断言。
1.4 何时使用断言?
- 从
any
缩小类型:当你比编译器更清楚变量的实际类型时(如动态解析的 API 响应)。 - 临时绕过复杂类型问题(但应尽量用更安全的方式替代)。
1.5 断言 vs. 不加断言对比
场景 | 不加断言 | 加断言 |
---|---|---|
类型安全性 | ❌ 无检查(any 的隐患) | ✅ 显式声明类型 |
运行时风险 | 可能隐藏错误 | 需开发者自己保证正确性 |
推荐程度 | ❌ 尽量避免 | ✅ 必要时使用,但优先用类型守卫 |
总结
- 不加断言:能运行,但失去类型安全性(尤其是
any
类型)。 - 加断言:明确类型意图,但需自行确保逻辑正确。
- 最佳实践:
- 尽量避免
any
,用更精确的类型。 - 优先用类型守卫(
typeof
、instanceof
)代替断言。 - 断言仅作为“最后手段”。
- 尽量避免