TS 环境搭建与基础属性
TS 环境搭建
安装环境依赖
- 通过 npm(Node.js 包管理器)
针对npm 用户可以安装包依赖
npm i typescript -g
然后再安装tsx 运行
npm i tsx -g
测试一下
- 在一个新的文件夹里面新建一个Basic1.ts 文件
- 写入如下代码
const getTime: () => void = () => {
console.log(new Date().toLocaleString());
};
getTime();
运行一下
tsx Basic1.ts
- 结果
2022/6/15 21:17:46
TS 基础类型
十二大类型
分成3(字符串,数字,布尔),3(null,object,undefined),2(array,tuple),2(any,unkonw),1(never),1(void) 方便记忆就是33,22,11
- 数字类型 number
- 字符串类型 string
- 布尔类型 boolean
- 空类型 null
- 对象类型 object
- 未定义类型 undefined
- 数组类型 array
- 元组类型 tuple
- 枚举类型 enum
- 任意类型 any
- 未知类型 unknown
- never类型 never
- 没有返回值类型 void
数字类型
- 整数类型 number
- 浮点数类型 number
- 大整数类型 bigint
const test_number_1: number = 100;
const test_number_2: number = 100.5;
const test_number_3: bigint = 100n;
console.log(test_number_1); // 100
console.log(test_number_2); // 100.5
console.log(test_number_3); // 100n
布尔类型
const test_boolean_1: boolean = true;
console.log(test_boolean_1); // true
const test_boolean_2: boolean = false;
console.log(test_boolean_2); // false
字符串类型
const test_string_1: string = "hello world";
console.log(test_string_1); // hello world
空类型 null
const test_null_1: null = null;
console.log(test_null_1); // null
未定义类型 undefined
const test_undefined_1: undefined = undefined;
console.log(test_undefined_1); // undefined
数组类型 array
const test_array_1: number[] = [1, 2, 3, 4, 5];
console.log(test_array_1); // [1, 2, 3, 4, 5]
const test_array_2: string[] = ["hello", "world"];
console.log(test_array_2); // ["hello", "world"]
// 数组和字符串混用
const test_array_3: (number | string)[] = [100, "hello", 200, "world"];
console.log(test_array_3); // [100, "hello", 200, "world"]
对象类型 object
- 使用
// 可以赋值对象、数组、函数等
const obj: object = {};
const arr: object = [1, 2, 3];
const fn: object = () => {};
对象类型 object 非常宽泛,只能访问对象共有的方法.比如(valueOf(),equals(),hashCode(),toString(),equals(),hashCode()).
- 限制
const person: object = { name: "Alice", age: 25 };
// ❌ 错误:不能访问具体属性
console.log(person.name); // Property 'name' does not exist on type 'object'
// ✅ 只能访问 Object 原型上的方法
console.log(person.toString());
- 如果是更精确的定义 我们一般使用接口来定义对象的属性和方法.
// 1. 对象字面量类型(推荐)
const person: { name: string; age: number } = { name: "Alice", age: 25 };
// 2. interface
interface Person {
name: string;
age: number;
}
const p: Person = { name: "Bob", age: 30 };
// 3. Record
const map: Record<string, number> = { a: 1, b: 2 };
// 4. 索引签名
const dict: { [key: string]: any } = {};
dict["name"] = "Alice";
dict["age"] = 25;
console.log(dict);
// { name: 'Alice', age: 25 }
- object vs Object vs {}
| 类型 | 说明 |
|---|---|
| object | 非原始类型(推荐用于"任意对象") |
| Object | JS 的 Object 构造函数类型,包含原始类型包装器 |
| {} | 空对象类型,几乎包含所有值(除 null / undefined ) |
- 举例
// object 不接受原始类型
const x: object = "hello"; // ❌ 错误
// Object 接受原始类型(自动装箱)
const y: Object = "hello"; // ✅ 可以
- 总结
需要 任意对象 时:用 object
需要 具体结构 时:用 interface / 类型别名 / 字面量类型
避免使用 Object 和 {} 作为类型,它们行为怪异
元组类型 tuple
- 元组(Tuple)是固定长度、固定类型的数组。
// 定义:第一个元素是 string,第二个是 number
const user: [string, number] = ["Alice", 25];
// 访问元素(类型已知)
const name = user[0]; // string
const age = user[1]; // number
// ❌ 越界访问会报错
const x = user[2]; // Tuple type '[string, number]' of length '2' has no element at index '2'
- 可选元素
// 第三个元素可选
const coords: [number, number, number?] = [10, 20];
// 或
const coords2: [number, number, number?] = [10, 20, 30];
- 剩余元素
// 前两个固定,后面任意多个 string
const log: [string, string, ...string[]] = [
"INFO",
"module",
"detail1",
"detail2",
];
- 只读元组
const point: readonly [number, number] = [10, 20];
// ❌ 不可修改
point[0] = 100; // Cannot assign to '0' because it is a read-only property
- 具名元组
const user: [name: string, age: number] = ["Alice", 25];
// 解构时更有语义
const [name, age] = user;
- 与数组的区别
| 特性 | 元组[string,number] | 数组(string | number)[] |
|---|---|---|---|
| 长度 | 固定 | 可变 | |
| 元素位置类型 | 每个位置类型固定 | 所有位置类型统一 | |
| 越界访问 | 报错 | 允许 |
- 实际使用场景
// useState 返回的就是元组
// [number, Dispatch<<SetStateAction<number>>]
const [count, setCount] = useState(0);
// 函数返回多个值
function getUser(): [string, number] {
return ["Alice", 25];
}
// CSV 行解析
const row: [string, string, number, boolean] = ["Alice", "Engineer", 25, true];
- 注意事项
push 不会检查类型的安全性,会破坏元组的类型约束。
// ❌ 长度不匹配
const bad: [string, number] = ["Alice"]; // 缺少元素
const bad2: [string, number] = ["Alice", 25, 1]; // 元素过多
// ⚠️ push 不会检查类型安全(设计限制)
const t: [string, number] = ["Alice", 25];
t.push("extra"); // 不报错,但破坏元组约束
枚举类型 enum
在 TypeScript 中,枚举(Enum)用于定义一组命名的常量。
- 数字枚举
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right, // 3
}
// 使用
const dir: Direction = Direction.Up;
// 反向映射:通过值获取名称
console.log(Direction[0]); // "Up"
console.log(Direction.Up); // 0
- 指定初始值
enum Status {
Pending = 1,
Processing, // 2
Done, // 3
Failed = 10,
Cancelled, // 11
}
- 字符串枚举
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE",
}
// 字符串枚举没有反向映射
const c: Color = Color.Red;
console.log(c); // "RED"
- 常量枚举(推荐)
编译时完全内联,不生成对象,性能更好:
const enum Permission {
Read = 1,
Write = 2,
Execute = 4,
}
// 编译后直接替换为值
const p = Permission.Read | Permission.Write; // 编译为 const p = 1 | 2
- 异构枚举(不推荐)
enum Mixed {
No = 0,
Yes = "YES",
}
- 实际应用
// 作为联合类型使用
enum HttpStatus {
OK = 200,
NotFound = 404,
ServerError = 500,
}
function handle(status: HttpStatus) {
switch (status) {
case HttpStatus.OK:
return "成功";
case HttpStatus.NotFound:
return "未找到";
default:
return "错误";
}
}
// 配置选项
const enum Feature {
DarkMode = 1,
AutoSave = 2,
Notification = 4,
}
let config = Feature.DarkMode | Feature.AutoSave;
- 注意事项
// 枚举成员在编译时确定,不能是变量
const start = 1;
enum Bad {
// A = start // ❌ 错误:const enum 成员只能使用常量
}
// 普通 enum 可以
enum Good {
A = start, // ✅ 可以
}
any 类型
在 TypeScript 中, any 是最宽松的类型,表示"任意类型",会关闭该变量的类型检查。
- 基本用法
let value: any = 4;
value = "hello"; // ✅ 不报错
value = true; // ✅ 不报错
value = {}; // ✅ 不报错
// 可以访问任意属性、调用任意方法
value.foo.bar(); // ✅ 编译不报错(运行可能报错)
- 使用场景
// 逐步迁移时,先标记为 any,后续再细化类型
function legacyFunction(data: any): any {
return data;
}
- 第三方库无类型定义
// 库没有 @types 声明文件
const untypedLib: any = require("some-untyped-lib");
- 动态内容
// JSON 解析结果
const parsed: any = JSON.parse(jsonString);
// 用户输入
const userInput: any = getDynamicData();
- 明确需要绕过类型检查
// 测试时临时绕过
const temp: any = complicatedObject;
- 危险操作
let x: any = "hello";
// 以下全部编译通过,但运行时可能崩溃
x.toFixed(2); // ❌ 运行时错误:字符串没有 toFixed
x[999].name; // ❌ 运行时错误
x(); // ❌ 运行时错误:不是函数
new x(); // ❌ 运行时错误
- 与unknown类型对比
unknown 是类型安全的 any
let a: any = 4;
a.toFixed(); // ✅ 编译通过(危险)
let u: unknown = 4;
u.toFixed(); // ❌ 错误:需要先类型收窄
// unknown 必须检查后才能使用
if (typeof u === "number") {
u.toFixed(); // ✅ 安全
}
| 特性 | any | unknown |
|---|---|---|
| 可赋值给任何类型 | ✅ | ❌ |
| 可访问任何属性 | ✅ | ❌ |
| 类型安全 | ❌ 关闭检查 | ✅ 必须收窄 |
| 推荐度 | 尽量避免 | 优先使用 |
- 最佳实践
// ❌ 滥用 any
function bad(data: any): any {
return data.map((x) => x.id);
}
// ✅ 尽量用具体类型或泛型
function good<T>(data: T[]): T[] {
return data;
}
// ✅ 不得不用时,优先 unknown
function better(data: unknown): void {
if (Array.isArray(data)) {
// 安全使用
}
}
// ✅ 类型断言(明确知道类型时)
function ok(data: unknown) {
const str = data as string;
return str.length;
}
- 总结
any = 关闭类型检查,编译器不再帮你
能不用就不用,用 unknown 或具体类型替代
遗留代码迁移时可用,但要逐步替换
开启 strict / noImplicitAny 防止隐式扩散
unknown 类型
unknown 是 TypeScript 3.0 引入的类型,它是 any 的安全替代品
| 特性 | any | unknown |
|---|---|---|
| 可以赋值给任何类型 | ✅ | ❌ |
| 任何类型可以赋值给它 | ✅ | ✅ |
| 可以任意访问属性/方法 | ✅ | ❌ |
| 使用前需要类型检查 | ❌ | ✅ |
- 基本用法
let a: unknown = 123;
a = "hello"; // OK
a = { x: 1 }; // OK
// ❌ 不能直接使用
let b: string = a; // Error: Type 'unknown' is not assignable to type 'string'
console.log(a.x); // Error: Object is of type 'unknown'
a.toFixed(); // Error
// ✅ 必须先缩小类型
if (typeof a === "number") {
a.toFixed(); // OK,此时 a 被收窄为 number
}
if (a instanceof Object) {
console.log((a as any).x); // 或者用类型断言
}
- 常用类型收窄方式
let val: unknown;
// 1. typeof
if (typeof val === "string") val.toUpperCase();
// 2. instanceof
if (val instanceof Date) val.getTime();
// 3. 自定义类型守卫
function isString(x: unknown): x is string {
return typeof x === "string";
}
// 4. 类型断言(确定时)
(val as string).toUpperCase();
- 实际场景
// API 返回不确定的数据
async function fetchData(): Promise<<unknown> {
const res = await fetch("/api");
return res.json(); // 返回 unknown 而非 any
}
// 安全处理
const data = await fetchData();
if (typeof data === "object" && data !== null && "id" in data) {
console.log(data.id); // OK
}
never 类型
never 表示 永远不会发生的值 的类型,它是 TypeScript 的底层类型(bottom type),所有类型的子类型。 一般用于抛出异常
- 函数永远不会返回
// 抛出异常
function throwError(msg: string): never {
throw new Error(msg);
}
// 无限循环
function infiniteLoop(): never {
while (true) {}
}
// 退出程序
function exit(): never {
process.exit(1);
}
- 穷尽性检查
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number }
| { kind: "rectangle"; width: number; height: number };
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle":
return Math.PI * shape.radius ** 2;
case "square":
return shape.side ** 2;
case "rectangle":
return shape.width * shape.height;
default:
// 如果上面漏了某个 case,这里会报错
const _exhaustive: never = shape;
return _exhaustive;
}
}
- 条件类型中的过滤
type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<string | null | undefined>; // string
- 与any/unknown的关系
| 类型 | 特性 |
|---|---|
| any | 顶层类型,可赋值给任何类型,也可接受任何类型 |
| unknown | 顶层类型,可接受任何类型,赋值前需检查 |
| never | 底层类型,可赋值给任何类型,但没有任何值属于它 |
- 举例说明
let n: never;
// never 可赋值给任何类型
let a: string = n; // OK
let b: number = n; // OK
// 没有任何类型(包括 never 自己)能赋值给 never
n = 1; // Error
n = ((): never => {
throw new Error();
})(); // OK
- 空数组的初始类型
// 不指定的话默认是 never[]
const arr: never[] = [];
// 推不出具体类型,通常应显式指定
const nums: number[] = [];
- 总结
never 主要用来表达"不可能"——函数不返回、分支不可达、类型过滤后的剩余。它在编译期帮你捕获遗漏的分支,是类型安全的重要工具。
void 类型
void 表示 没有返回值 或 返回值为 undefined ,主要用于函数。
- 基本用法
// 函数没有 return,或 return 不带值
function log(msg: string): void {
console.log(msg);
// 没有 return
}
function noop(): void {
return; // return 不带值,也是 void
}
// 变量声明为 void,只能赋 undefined 或 null(非严格模式下)
let v: void = undefined;
- 与undefined的区别
| 使用 | void | undefined |
|---|---|---|
| 用途 | 函数返回类型 | 值类型 |
| 含义 | 不care返回值 | 值就是undefined |
| 函数实现 | 可以没有return,或return空 | 必须return undefined |
- 举例
// void:不关心返回什么
function f1(): void {
console.log(1);
}
// undefined:必须返回 undefined
function f2(): undefined {
console.log(1);
return undefined; // 必须写 return
}
- 实际场景
- 回调函数
// 不处理回调的返回值
arr.forEach((item): void => {
console.log(item);
});
// 错误:回调返回了值,但类型要求 void
// forEach 要求 (item) => void,返回值被忽略
const nums = [1, 2, 3];
nums.forEach((n) => n * 2); // 不报错,但返回值被忽略
- 接口方法
interface Logger {
log(msg: string): void; // 只要求调用,不要求返回值
error(msg: string): void;
}
class ConsoleLogger implements Logger {
log(msg: string) {
console.log(msg);
// 不需要 return
}
error(msg: string) {
console.error(msg);
}
}
- 泛型约束中的忽略
// Promise<void>:异步操作完成,但没有结果值
async function save(): Promise<void> {
await fetch("/api/save");
// 没有 return
}
// 对比
async function load(): Promise<string> {
const res = await fetch("/api/data");
return res.text(); // 返回 string
}
- 注意点
// void 的返回值可以被赋值为 undefined
const x: void = undefined;
// 但 void 类型的表达式不能赋值给其他类型
function f(): void {}
const a: number = f(); // Error: Type 'void' is not assignable to type 'number'
// 箭头函数简写要注意
const handler1 = () => console.log(1); // () => void
const handler2 = () => {
console.log(1);
}; // () => void
const handler3 = () => 1; // () => number
- 总结:
void 表达"执行操作,不期待结果"。函数签名用它,调用方就知道不需要处理返回值。
评论区