TypeScript入门指南:零基础也能快速掌握核心语法
一、TS的诞生:解决JS弱类型痛点
JavaScript作为典型的弱类型语言,灵活性与隐患并存。无需提前声明变量类型、运行时自动推导的特性,在小项目中游刃有余;一旦进入团队协作或大型企业级开发,类型不匹配、隐式转换等问题就会频繁暴露,导致调试成本骤增。
// 示例:JS中无类型约束的相加函数
function add(a, b) {
return a + b;
}
add(1, '2'); // 结果是"12",而非预期的3
上述案例中,本应执行数值相加的函数,因传入字符串参数而返回拼接结果"12"。这类错误无法在代码编写阶段被检测,只能在运行时人工排查。TypeScript作为JavaScript的超集,核心目标正是引入强类型约束——要求变量和函数在定义时显式声明类型,使类型不匹配问题在编译阶段即可暴露,避免线上隐患。团队成员也不再需要反复协商「此函数应传入何种参数」——类型定义一目了然。
二、TS的编译与运行:从安装到执行
浏览器仅支持原生JavaScript,无法直接运行TS代码,因此需将TS编译为JS。核心工具链包含以下两个:
1. TS编译器(typescript)
全局安装编译器:
npm i -g typescript
安装后验证版本:
tsc -v # 查看版本
将TS文件编译为JS,例如处理 3.ts:
tsc 3.ts # 生成对应的3.js文件
若不想全局安装,可通过 npx 临时调用:
npx tsc 3.ts
2. 直接运行TS的引擎(ts-node)
若希望跳过「编译→运行」两步流程,直接执行TS代码,可安装 ts-node:
npm i -g ts-node
验证安装:
ts-node -v
直接运行TS文件:
ts-node 3.ts # 直接输出结果
三、TS基础类型:为变量「贴标签」
TS兼容JavaScript所有原生类型,同时扩展了专属类型。核心分类如下:
1. 基础原始类型
与JavaScript一致,但声明时必须显式指定类型:
// 布尔型
let isDone: boolean = false;
// 数字型(包含整数、浮点数、NaN等)
let count: number = 123;
// 字符串型
let str: string = 'hello';
// 符号型
const sym: symbol = Symbol();
// 未定义/空值(是所有类型的子类型)
let u: undefined = undefined;
let n: null = null;
2. 数组与元组
-
普通数组:仅允许存放同一类型数据。提供两种声明方式:
// 方式1:类型[] const list: number[] = [1, 2, 3]; // 方式2:泛型写法(后续详解) let arr: Array<number> = [1, 2, 3]; // 若需存放多种类型,可用联合类型 let mixArr: Array<number | string> = [1, 2, '3']; -
元组(Tuple):固定长度、按顺序指定成员类型的特殊数组:
// 第一个元素必须为number,第二个必须为string let tuple: [number, string] = [100, 'hello'];
3. 枚举类型(Enum)
枚举为常量集合赋予可读名称,变量取值仅限于枚举项:
enum Direction {
North, // 默认值0,也可自定义:North = '北'
South,
East,
West
}
// dir的值仅能为Direction.North/South/East/West
let dir: Direction = Direction.North;
4. 任意类型(any)与未知类型(unknown)
二者均表示「类型不确定」,但安全级别截然不同:
-
any:彻底放弃类型检查,可赋值给任何类型变量。应严格控制使用,否则将退化至JavaScript的弱类型状态:
let notSure: any = 100; notSure = 'hello'; // 合法 let abc: string = notSure; // 合法(any可赋值给string) -
unknown:相对安全,不能直接赋值给其他类型变量,需经过类型守卫或断言:
let value: unknown = 123; value = 'hello'; // 合法 let abc: string = value; // 报错(unknown不可直接赋值给string)
5. 函数相关类型
-
void:标识无返回值的函数:
function logMsg(): void { console.log('hello'); } -
函数类型:函数本身可作为类型,常用于高阶函数或回调场景:
function getUser(): Function { return function(): number { return 123; } }
四、TS对象类型:区分不同「对象」范畴
TS对「对象」的划分非常细致,核心包含三种形态:
// 1. 小写object:狭义对象(仅包含对象、数组、函数)
const obj: object = { name: '张三' };
const arrObj: object = [1, 2, 3];
const funcObj: object = () => {};
// 2. 大写Object:广义对象(几乎涵盖所有值,类似any)
const obj2: Object = 123; // 合法(数字属于广义Object)
const obj3: Object = 'hello'; // 合法
// 3. 空对象{}:不允许添加任何属性
const emptyObj: {} = {};
emptyObj.a = 123; // 报错
特殊:值类型
将具体值本身用作类型声明,使变量仅能等于该值(即字面量类型):
const hello: 'hello' = 'hello';
hello = 'world'; // 报错(仅限于'hello')
五、TS进阶手段:让类型更「智能」
1. 类型推导
TS编译器会根据变量初始值自动推断类型,减少显式声明的冗余:
let num = 123; // 编译器自动将num推定为number类型
num = 'hello'; // 报错(类型已固定)
2. 类型断言
当开发者比编译器更了解变量真实类型时,可手动向编译器声明类型。两种写法:
let someValue: any = 'this is a string';
// 写法1:as 类型(推荐,兼容JSX)
let strLength1 = (someValue as string).length;
// 写法2:<类型>值(不兼容JSX)
let strLength2 = (someValue).length;
注意:不可将完全不相关的类型进行断言,例如将number断言为string是非法的。
3. 类型守卫
在运行时通过条件判断,确保变量属于指定类型后再执行操作,避免类型错误:
interface Person {
name: string;
age: number;
sex?: unknown;
}
const p: Person = { name: '张三', age: 18 };
// 类型守卫:检查p.sex是否为string类型
if (typeof p.sex === 'string') {
console.log(p.sex.length); // 仅在确认string类型后安全调用length
}
六、TS类型定义:interface与type
当基础类型无法满足需求时,TS提供 interface 和 type 两种自定义类型方案。核心差异如下:
1. 接口(interface)
主要用于定义对象结构,支持扩展与实现:
interface Person {
name: string; // 必选属性
age: number;
sex?: unknown; // 可选属性
}
// 实现接口
const p: Person = {
name: '张三',
age: 18,
// sex为可选属性,可省略
};
2. 类型别名(type)
功能更为灵活,可定义对象、联合类型、交叉类型等:
// 定义基础类型别名
type StrType = string;
const a: StrType = 'hello';
// 联合类型(变量可为多种类型之一)
type UnionType = string | number | boolean;
const b: UnionType = 123; // 合法
const c: UnionType = 'hello'; // 合法
// 交叉类型(合并多个类型,需同时满足所有约束)
type PartailX = { x: number };
type Point = PartailX & { y: number };
const p: Point = { x: 100, y: 200 }; // 必须同时包含x和y
七、TS泛型:让代码「复用且类型安全」
泛型是TS最核心的特性之一,用于解决「类型不确定但需保持类型一致」的场景,常见于函数、数组等。
1. 函数泛型
当函数参数或返回值类型未知,但要求入参与返回类型匹配时,使用泛型:
// T为类型变量,调用时确定具体类型
function identity(value: T): T {
return value;
}
// 调用时指定T的类型
identity<number>(123);
// 或由编译器自动推导
identity('hello');
// 多个泛型参数
function identity2(value: T, msg: U): T {
console.log(msg);
return value;
}
identity2<number, string>(123, 'hello');
2. 数组泛型
前文已提及,它是泛型的具体应用。Array 与 number[] 完全等价:
// Array 和 number[] 等价
let arr: Array<number> = [1, 2, 3];
// 配合联合类型使用
let mixArr: Array<number | string> = [1, 2, '3'];
总结
回到最初的问题:TypeScript究竟能带来什么价值?一句话概括——强类型约束。从基础类型、对象类型到泛型、类型守卫,TS所有特性均围绕同一个目标:让代码「类型可预测、错误早发现」。
在中小型项目中,TS可能增加少量初始开发成本;但在大型团队协作场景下,这份「类型约束」的价值立竿见影——大幅降低调试与沟通成本。这也是React、Vue等主流框架纷纷推荐使用TS的原因。
从今天开始,尝试将TS融入你的开发流程吧。从基础类型声明到泛型封装,逐步吃透,你会发现前端代码其实可以更「严谨」。不妨动手试试?