TypeScript 总结
TypeScript 总结
概述
TypeScript 是微软开放的开源编程语言,是 JavaScript 的超级。
特性:
- 类型安全:编译时捕获错误,减少运行时 bug。
- IDE 更好的支持:智能提示/自动补全/重构工具。
- 代码可维护性:清晰的类型定义让代码更容易理解。
- 最新 ES 特性:支持最新的 JavaScript 特性。
运行ts文件
无论是在浏览器环境下,还是在Node环境下,TypeScript程序都是不能直接运行的。

方式一:将TypeScript编译为JavaScript后运行
一、安装typescript:
npm install -g typescript
二、将ts文件编译为js文件:
tsc code.ts
三、运行js文件:
node code.js
查看tsc版本:
tsc -v
使用ES5编译ts代码:
tsc -t es5 demo.ts
方式二:直接运行TypeScript文件
一、安装ts-node:
npm install -g ts-node
二、执行 tsc --init 命令,生成 tsconfig.json 配置文件。
三、运行ts文件:
ts-node code.ts
四、或者通过 VSCode 中的 Code Runner 插件运行。
五、配置 tsconfig.json
创建 tsconfig.json:
tsc --init
tsconfig.json 说明:
{
"compilerOptions": {
"target": "ES2020", // 编译目标
"module": "commonjs", // 模块系统
"lib": ["ES2020"], // 包含的库文件
"outDir": "./dist", // 输出目录
"rootDir": "./src", // 源代码目录
"strict": true, // 严格模式
"esModuleInterop": true, // ES 模块互操作
"skipLibCheck": true, // 跳过库文件检查
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
TypeScript VS JavaScript
// JavaScript
function add(a, b) {
return a + b;
}
const ret = add(1, "2")
console.log(ret) // 12
// TypeScript
function add(a: number, b: number): number {
return a + b;
}
// const ret = add(1, "2") // 编译时报错
const ret = add(1, 2)
console.log(ret) // 3
类型
- 使用 let 关键字声明变量
- 使用 const 关键字声明常量
基本类型
// 布尔类型
let isFlag: boolean = false;
// 数值类型
let binary: number = 0b1010 // 二进制
let octal: number = 0o123 // 八进制
let decimal: number = 6 // 十进制
let hex: number = 0x123 // 十六进制
let infinity: number = Infinity // 无穷大
// 字符串
let color: string = 'red';
let name: string = "小明"
let info: string = `hello ${name}`
// 数组
let arr1: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]
// 元组
let x: [string, number]
x = ["hello", 1]
console.log(x[0]) // hello
console.log(x[1]) // 1
// null和 undefined
let a: null = null
let b: undefined = undefined
// any:任意类型,没有类型检查
let a: any = "hello"
a = 10
a = true
console.log(a) // true
// unknow:未知类型,有类型检查
let a: unknown = 1.5
// let ret = Math.round(a) // 提示错误
if (typeof a === 'number') {
let ret = Math.round(a)
}
// void:没有返回值
function add(a: number, b: number): void {
console.log(a + b);
}
// never:没有值
function error(message: string): never {
throw new Error(message);
}
// object
let obj: object = {name: "小明", age: 18}
any、object和unknown区别
- any:任意类型,完全绕过类型检查,安全性低。
- object: 非原始类型(除string/number/boolean/symbol/null/undefined外),安全性中等。
- unknown:未知类型,类型安全的any,推荐使用,需要通过类型检查或断言后使用。
类型断言
类型断言:指开发者手动告诉编译器某个值的具体类型的方式,也称为类型适配。
类型断言的2种方式:
- 方式一:尖括号语法
- 方式二:as 语法
// 方式一
let str: any = "hello world"
let len = (<string>str).length
// 方式二
let str: any = "hello world"
let len = (str as string).length
使用类型断言前:
function getLength(x: number | string): number {
if (typeof x === "number") {
return x.toString().length
} else {
return x.length
}
}
console.log(getLength(10)) // 2
console.log(getLength("abc")) // 3
使用类型断言后:
function getLength(x: number | string): number {
if ((<string>x).length) {
return (x as string).length
} else {
return x.toString().length
}
}
console.log(getLength(10)) // 2
console.log(getLength("abc")) // 3
接口
- 声明接口用 interface 关键字
- 实现接口用 implements 关键字
- 接口继承用 extends 关键字
基本用法
interface IPerson {
id: number
name: string
age: number
sex: boolean
sum(x: number, y: number): number
}
const person: IPerson = {
id: 1,
name: "小明",
age: 18,
sex: true,
sum: function (x: number, y: number): number {
return x + y
},
}
console.log(person) // { id: 1, name: '小明', age: 18, sex: true, sum: [Function: sum] }
可选属性
interface IPerson {
id: number
name: string
age?: number
sex?: boolean
sum?(x: number, y: number): number
}
const person: IPerson = {
id: 1,
name: "小明",
}
console.log(person) // { id: 1, name: '小明' }
只读属性
在属性名前加上 readonly 关键字表示只读属性,值一旦被定义则不能被修改。
interface IPerson {
readonly id: number
name: string
age?: number
sex?: boolean
sum?(x: number, y: number): number
}
const person: IPerson = {
id: 1,
name: "小明",
}
// person.id = 2 // 报错,只读属性不能修改
函数类型接口
在 TypeScript 中可以利用接口定义函数类型。
interface SumFn {
(x: number, y: number): number
}
const mySum: SumFn = (x, y) => x + y
console.log(mySum(1, 2)) // 3;
可索引类型
TypeScript 的可索引类型(Indexable Types)通过 索引签名 定义动态属性访问规则,是处理数组、字典等动态数据结构的核心工具。
语法格式:[keyType: KeyType]: ValueType
- KeyType:索引键类型
- ValueType:索引值类型
// 数字索引
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["hello", "world"];
let a = myArray[0];
console.log(a); // hello
// 字符串索引
interface UserMap {
[key: string]: { name: string; age: number };
}
const users: UserMap = {
a: {name: "小白", age: 19},
b: {name: "小黑", age: 30}
};
console.log(users["a"]);
接口继承
interface Shape {
color: string;
}
interface Square extends Shape {
slideLength: number;
}
let squares: Square = {
color: "RED",
slideLength: 5,
};
console.log(squares);
类
- 声明类用 class 关键字
- 创建对象用 new 关键字
- 类继承用 extends 关键字
基本用法
class Person {
// 属性:
name: string
age: number
// 静态属性:
static nationality: string = "China"
// 构造函数:
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 方法:
sayHello() {
console.log(`Hello, my name is ${this.name}`)
}
// 静态方法:
static sayNationality() {
console.log(`我的国籍是${Person.nationality}`)
}
}
let p = new Person("Tom", 18)
p.sayHello() // Hello, my name is Tom
Person.sayNationality() // 我的国籍是China
继承
class Animal {
eat(food: string) {
console.log(`吃${food}`)
}
}
class Dog extends Animal {
call() {
console.log("汪汪汪")
}
}
const dog = new Dog()
dog.eat("骨头") // 吃骨头
dog.call() // 汪汪汪
访问修饰符
- public:公开的属性或方法。
- private:私有属性或方法,只能在该类的内部访问。
- protected:受保护的属性或方法,支持在子类中访问。
class Employee {
public name: string; // 公开
private salary: number; // 私有
protected department: string; // 受保护
constructor(name: string, salary: number, department: string) {
this.name = name;
this.salary = salary;
this.department = department;
}
public getDetails(): string {
return `${this.name} ${this.getSalary()} ${this.department}`;
}
private getSalary(): number {
return this.salary;
}
}
let xiaoming = new Employee("小明", 2000, "研发部门");
console.log(xiaoming.getDetails());
getter和setter
class Person {
private _age: number = 0;
get age() {
return this._age;
}
set age(value: number) {
if (value < 0) {
throw new Error("Age must be greater than 0");
}
this._age = value;
}
}
let person = new Person();
person.age = 5;
console.log(person.age);
抽象类
abstract class Animal {
abstract eat(): void
run() {
console.log("奔跑");
}
}
class Dog extends Animal {
eat() {
console.log("吃骨头");
}
}
const dog = new Dog();
dog.eat(); // 吃骨头
dog.run(); // 奔跑
多态
class Animal {
name: string
constructor(name: string) {
this.name = name
}
eat(food: string = "食物") {
console.log(`${this.name} 吃 ${food}`)
}
}
class Dog extends Animal {
constructor(name: string) {
super(name)
}
eat(food: string = "骨头") {
super.eat(food)
}
}
class Cat extends Animal {
constructor(name: string) {
super(name)
}
eat(food: string = "鱼") {
super.eat(food)
}
}
function eat(animal: Animal) {
animal.eat()
}
eat(new Dog("旺财")) // 旺财 吃 骨头
eat(new Cat("咪咪")) // 咪咪 吃 鱼
函数
TypeScript 是 JavaScript 的超集,JavaScript 的一些特性 TypeScript 中依然存在。
此外,TypeScript函数还增加了函数类型、可选参数、默认参数及剩余参数等。
JavaScript函数:
// 命名函数
function add1(x, y) {
return x + y;
}
// 匿名函数
const add2 = function (x, y) {
return x + y;
};
// 箭头函数
const add3 = (x, y) => x + y;
TypeScript函数:
// 命名函数
function add1(x: number, y: number): number {
return x + y;
}
// 匿名函数
const add2 = function (x: number, y: number): number {
return x + y;
};
// 箭头函数
const add3 = (x: number, y: number) => x + y;
函数类型
// 函数类型
const add4: (x: number, y: number) => number = (x: number, y: number) => x + y;
可选参数
function getName(firstName: string, lastName?: string): string {
if (lastName) {
return firstName + lastName;
}
return firstName;
}
console.log(getName("李"));
console.log(getName("李", "白"));
默认参数
function getName(firstName: string, lastName: string = "白"): string {
if (lastName) {
return firstName + lastName;
}
return firstName;
}
console.log(getName("李"));
console.log(getName("李", "黑"));
剩余参数
如果想同时操作多个参数,或者并不能明确知道会有多少个参数传递进来,就可以使用剩余参数。
function showSports(sport: string, ...others: string[]) {
console.log(sport);
console.log(others.join("-"));
}
showSports("足球", "篮球", "乒乓球");
// 足球
// 篮球-乒乓球
函数重载
function makeDate(timestamp: number): Date
function makeDate(year: number, month: number, day: number): Date
function makeDate(timestampOrYear: number, month?: number, day?: number): Date {
if (month != null && day != null) {
return new Date(timestampOrYear, month - 1, day)
} else {
return new Date(timestampOrYear)
}
}
console.log(makeDate(1688368612562)) // 2023-11-01T00:36:52.562Z
console.log(makeDate(2008, 9, 10)) // 2008-09-09T16:00:00.000Z
泛型
泛型函数
function createArray<T>(length: number, value: T): T[] {
let result: T[] = []
for (let i = 0; i < length; i++) {
result[i] = value
}
return result
}
const arr = createArray<string>(3, "x")
console.log(arr) // ['x', 'x', 'x']
泛型接口
interface IBaseCRUD<T> {
add: (t: T) => void;
getById: (id: number) => T | undefined;
getAll: () => T[];
}
class User {
id?: number; // id自增
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class UserCRUD implements IBaseCRUD<User> {
private data: User[] = [];
add(user: User): void {
user.id = this.data.length + 1;
this.data.push(user);
}
getById(id: number): User | undefined {
return this.data.find((user) => user.id === id);
}
getAll(): User[] {
return this.data;
}
}
const userCRUD = new UserCRUD();
userCRUD.add(new User("a", 1));
userCRUD.add(new User("b", 2));
userCRUD.add(new User("c", 3));
console.log(userCRUD.getById(1));
// User { id: 1, name: 'a', age: 1 }
console.log(userCRUD.getAll());
// [
// User { id: 1, name: 'a', age: 1 },
// User { id: 2, name: 'b', age: 2 },
// User { id: 3, name: 'c', age: 3 }
// ]
泛型类
abstract class GenericData<T> {
abstract add(x: T, y: T): T
}
class NumberData extends GenericData<number> {
add(x: number, y: number) {
return x + y;
}
}
class StringData extends GenericData<string> {
add(x: string, y: string): string {
return x + y;
}
}
const numberData = new NumberData();
const result1 = numberData.add(11, 22);
console.log(result1); // 33
const stringData = new StringData();
const result2 = stringData.add("hello", "world");
console.log(result2); // helloworld
泛型约束
不使用接口:
function show<T extends Object>(x: T): void {
console.log(x)
}
show<{ name: string; age: number }>({ name: "小明", age: 18 }) // { name: '小明', age: 18 }
使用接口:
function show<T extends Object>(x: T): void {
console.log(x)
}
interface IUser {
name: string
age: number
}
show<IUser>({ name: "小明", age: 18 })
使用接口继承:
interface IUser {
name: string
age: number
}
function show<T extends IUser>(x: T): void {
console.log(x)
}
show({ name: "小明", age: 18 })
枚举
基本用法
enum Color {
RED,
GREEN,
BLUE
}
let c: Color = Color.RED;
console.log(c) // 0
自定义枚举
enum Sports {
BASKETBALL = "篮球",
FOOTBALL = "足球"
}
let s: Sports = Sports.BASKETBALL;
console.log(s) // 篮球
const enum Status {
LOADING = 0,
ERROR = 1,
SUCCESS = 2,
}
let status = Status.SUCCESS;
console.log(status); // 2
高级类型
类型别名
// 基础类型
type Name = string
type Age = number
let name: Name = "小明";
let age: Age = 18;
console.log(`${name} ${age}`);
// 函数类型
type User = (name: Name, age: Age) => string
const user: User = (name: Name, age: Age) => {
return `${name} ${age}`;
};
let ret = user("小白", 28);
console.log(ret); // 小白 28
// 对象类型
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
type persons = Person[];
let persons: Person[] = [new Person("小白", 18), new Person("小黑", 28)];
console.log(persons);
// [ Person { name: '小白', age: 18 }, Person { name: '小黑', age: 28 } ]
交叉类型
交叉类型使用 &符号,将多个类型合并为一个新类型,新类型需同时满足所有原始类型的属性和方法。
语法格式:type NewType = TypeA & TypeB & …
interface Person {
name: string;
age: number;
}
interface Department {
departmentId: number;
departmentName: string;
}
type Employee = Person & Department;
const employee: Employee = {
name: "小明",
age: 18,
departmentId: 100,
departmentName: "研发部",
};
console.log(employee);
// { name: '小明', age: 18, departmentId: 100, departmentName: '研发部' }
联合类型
联合类型使用 |符号,表示变量可以是多种类型中的任意一种。
语法格式:type NewType = TypeA | TypeB | …
type NameAge = string | number;
function showNameAge(nameAge: NameAge) {
if (typeof nameAge === "number") {
console.log(`年龄:${nameAge}`);
} else {
console.log(`姓名:${nameAge}`);
}
}
showNameAge("小明"); // 姓名:小明
showNameAge(18); // 年龄:18
// 限制输入
type Color = "RED" | "BLUE" | "GREEN"
function showColor(color: Color) {
console.log(`颜色:${color}`);
}
showColor("RED");
// showColor("ABC"); // 报错
类型守卫
type Circle = {
radius: number
}
type Rectangle = {
width: number
height: numbera
}
type Shape = Circle | Rectangle
function calculateArea(shape: Shape): number {
if ("radius" in shape) {
return Math.PI * shape.radius ** 2
} else {
return shape.width * shape.height
}
}
let shape: Shape = { radius: 10 }
console.log(calculateArea(shape)) // 314.1592653589793
let shape2: Shape = { width: 10, height: 20 }
console.log(calculateArea(shape2))
类型守卫
作用:
- 在运行时验证变量是否符合预期类型,避免因联合类型或
any类型导致的潜在错误。 - 通过条件分支(如
if/else、switch)将宽泛类型(如string | number)逐步收窄为具体类型。 - 确保在特定作用域内变量类型确定,允许安全访问属性或调用方法。
方式:
- typeof类型守卫:适合检查基本类型
- instanceof类型守卫:适合检查对象是否为某个类的实例
- in操作符类型守卫:适合检查对象是否包含指定属性
- 自定义类型守卫:适合复杂类型
- 可辨识联合:通过公共属性区分
typeof类型守卫
function getNameOrAge(value: string | number) {
if (typeof value === "string") {
return `姓名:${value}`;
} else if (typeof value === "number") {
return `年龄:${value}`;
} else {
throw new Error("类型错误");
}
}
instanceof类型守卫
class Bird {
fly() {
console.log("飞翔");
}
}
class Fish {
swim() {
console.log("游泳");
}
}
function move(animal: Bird | Fish) {
if (animal instanceof Bird) {
animal.fly();
} else if (animal instanceof Fish) {
animal.swim();
}
}
in操作符类型守卫
interface Swimmer {
swim(): void;
}
interface Runner {
run(): void;
}
function move(animal: Swimmer | Runner) {
if ("swim" in animal) {
animal.swim();
} else if ("run" in animal) {
animal.run();
}
}
自定义类型守卫
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
function isCat(pet: Cat | Dog): pet is Cat {
return (pet as Cat).meow !== undefined;
}
function makeSound(pet: Cat | Dog) {
if (isCat(pet)) {
pet.meow();
} else {
pet.bark();
}
}
可辨识联合
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(shape: Shape): number {
switch (shape.kind) {
case "square":
return shape.size * shape.size;
case "rectangle":
return shape.width * shape.height;
case "circle":
return Math.PI * shape.radius ** 2;
default:
throw new Error("类型错误");
}
}
非空操作和可选链
interface User {
name: string;
address?: {
city: string;
street: string;
};
}
const user1: User = {name: "小白"};
const user2: User = {name: "小黑", address: {city: "北京市"}};
可选链操作符
如果可选链左侧的值为null或undefined,则表达式返回undefined,不再执行右侧代码。
const city1 = user1.address?.city;
console.log(city1); // undefined
const city2 = user2.address?.city;
console.log(city2); // 北京市
类型断言操作符
类型断言表示告诉编译器该值存在,不进行空值检查,如果断言错误,运行时会抛出 TypeError。
let city = user2.address!.city;
console.log(city); // 北京市
空值合并操作符
如果左侧的值为null或undefined,则返回右侧的值。
let city = user1.address?.city ?? "unknow";
console.log(city); // unknow
模块化
TypeScript 支持多种模块系统,包含:ESM(ES模块)、CJS(CommonJS)等。
- EMS:现在JavaScript标准,使用 import 和 export 语法。
- CJS:Node.js默认模块系统,使用 require() 和 module.exports 语法。
导出
export function add(x: number, y: number): number {
return x + y;
}
export function minus(x: number, y: number): number {
return x - y;
}
export const PI = Math.PI;
export default class Calculator {
add(x: number, y: number) {
return x + y;
}
}
导入
import Calculator, {add, minus, PI} from "./math";
console.log(add(11, 22));
console.log(minus(22, 11));
console.log(PI);
let calculator = new Calculator();
console.log(calculator.add(1, 2));
命名空间
命名空间是 TypeScript 早期的模块化解决方案,现在更推荐使用 ES 模块。但在一些场景下仍然有用:
命名空间使用 namespace 关键字定义。
namespace MathTool {
export function add(a: number, b: number): number {
return a + b
}
export function sub(a: number, b: number): number {
return a - b
}
export function mul(a: number, b: number): number {
return a * b
}
export function div(a: number, b: number): number {
return a / b
}
}
使用:
console.log(MathTool.add(1, 2)) // 3;
console.log(MathTool.sub(1, 2)) // -1;
console.log(MathTool.mul(1, 2)) // 2;
console.log(MathTool.div(1, 2)) // 0.5;
其他
interface和type区别
- interface:主要用于定义对象结构,描述对象的形状。
- type:定义类型别名,可以表示任何类型,包含:原始类型、联合类型、交叉类型等。
更多推荐

所有评论(0)