TypeScript 基础知识
什么是 TypeScript
TypeScript 是 JavaScript 的超集,它为 JavaScript 提供了静态类型检查和其他一些特性,以帮助开发者编写更可维护、可读性更强的代码。TypeScript 最终会被编译为标准的 JavaScript 代码,因此可以运行在任何支持 JavaScript 的环境中。
安装 TypeScript
1.可以使用 npm 安装 TypeScript
:
js
npm install -g typescript
2.编译: tsc 文件名
- 编辑完成后会在当前文件所在目录的同级, 创建一个名字一样的 JS 文件,内部的 ts 代码会被编译成 js 代码, 原本的 js 代码 原封不动
- 如果当前文件内, 没有 ts 代码, 全都是 js 代码, 我们可以直接使用 node 运行当前文件;否则会报错, 需要使用 tsc 编译成 js 文件后, 在使用。
- 安装
ts-node
:
js
npm i ts-node -g
- 当前的这个第三方包会给我们提供一个 node 环境, 然后去运行我们的 ts 代码;当前的第三方包在运行的时候, 会自动帮我们把 ts 代码做一个编译处理, 然后将编译完成的代码运行到 node 环境中.
- 注意: 当前第三方包只会帮我们解析运行 ts 代码, 并不会帮我们创建对应的 js 文件
基本类型
TypeScript 支持多种基本数据类型:
number
:数字类型string
:字符串类型boolean
:布尔类型null
和undefined
:空类型object
:对象类型array
:数组类型tuple
:元组类型enum
:枚举类型any
:任意类型(any 表示不确定当前变量具体的值是什么, 或者这个变量的值类型有可能会出现多个)void
:表示没有任何返回值的函数
ini
let num: number = 5;
let str: string = "Hello";
let bool: boolean = true;
let nul: null = null;
let und: undefined = undefined;
let obj: object = { key: "value" };
let arr: number[] = [1, 2, 3];
let tpl: [string, number] = ["tuple", 10];
enum Color { Red, Green, Blue };
let color: Color = Color.Red;
let anyType: any = "anything";
let voidFunc: void = () => { console.log("This function returns nothing."); };
函数
定义函数时可以指定参数类型和返回值类型:
typescript
function add(x: number, y: number): number {
return x + y;
}
let result: number = add(3, 5);
数组
在 TypeScript 中,数组可以使用以下方式定义:
js
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: string[] = ["apple", "banana", "orange"];
// arr3 是一个数组, 数组内数据的类型, 不做校验
const arr3: any[] = [100, "qf001", true, undefined, null];
// arr4 是一个数组, 数组内的数据是 字符串或者数字
// const arr4: number[] = [100, 'QF001', 200]
// const arr4: string[] = [100, 'QF001', 200]
const arr4: (number | string)[] = [100, "QF001", 200];
// 数组内部是由多个对象组成的
const arr5: { id: number; text: string }[] = [
{ id: 1, text: "qf001" },
{ id: 2, text: "qf002" },
{ id: 3, text: "qf003" },
{ id: 4, text: "qf004" },
];
// 利用接口改造上述代码
interface IArr6 {
id: number;
text: string;
}
const arr6: IArr6[] = [
{ id: 1, text: "qf001" },
{ id: 2, text: "qf002" },
{ id: 3, text: "qf003" },
{ id: 4, text: "qf004" },
];
也可以使用数组泛型:
js
// 利用 泛型 添加数组类型
interface IArr7 {
id: number;
text: string;
}
const arr7: Array<IArr7> = [
{ id: 1, text: "qf001" },
{ id: 2, text: "qf002" },
{ id: 3, text: "qf003" },
{ id: 4, text: "qf004" },
];
const arr8: Array<number> = [1, 2, 3];
const arr9: Array<string> = ["1", "2", "3"];
数组元素的访问和操作:
ini
let numbers: number[] = [1, 2, 3, 4, 5];
let firstNumber: number = numbers[0]; // 访问第一个元素
numbers.push(6); // 添加元素
numbers.pop(); // 移除最后一个元素
对象
在 TypeScript 中,对象是一种复合值,它可以包含多个属性,每个属性都有自己的名称和值。以下是一些关于对象的基础知识:
1. 对象的定义
对象可以通过直接赋值或使用接口来定义:
interface 接口名 (一般: I + 变量的名字) {}
typescript
// 直接赋值
let person: { name: string; age: number } = {
name: "John",
age: 30,
};
// 使用接口
interface Person {
name: string;
age: number;
}
let anotherPerson: Person = {
name: "Jane",
age: 25,
};
//接口的嵌套
interface IObj {
name: string,
id: number,
info: {
width: number,
height: number,
bo: boolean
}
}
// 如果 接口IInfo 使用次数比较多, 可以抽离出来, 否则不建议
interface IInfo {
width: number;
height: number;
bo: boolean;
}
interface IObj {
name: string;
id: number;
info: IInfo
}
const obj: IObj = {
name: "qf001",
id: 10086,
info: {
width: 100,
height: 200,
bo: true,
},
};
// obj.info.bo = '10086' // 不能将类型 "string" 分配给类型 "boolean"
console.log(obj.info.bo);
2. 可选属性
在接口中,你可以使用问号 ?
表示属性是可选的:
typescript
interface Car {
brand: string;
model?: string; // 可选属性
year: number;
}
let myCar: Car = {
brand: "Toyota",
year: 2020,
};
3. 只读属性
你可以使用 readonly
关键字使属性成为只读的:
typescript
interface Point {
readonly x: number;
readonly y: number;
}
let point: Point = { x: 10, y: 20 };
// point.x = 30; // 编译错误,无法修改只读属性
4. 函数作为属性
对象的属性可以是函数,被称为方法:
typescript
interface Greeter {
greet(): string;
}
let myGreeter: Greeter = {
greet() {
return "Hello, TypeScript!";
},
};
5. 类型断言和对象
使用类型断言可以告诉编译器对象的实际类型:
typescript
let value: any = "Hello, TypeScript!";
let strLength: number = (value as string).length;
6. 展开运算符
使用展开运算符 ...
可以合并对象的属性:
typescript
let defaults: { food: string; price: number } = { food: "Pizza", price: 10 };
let order: { toppings: string[]; } = { toppings: ["Cheese", "Pepperoni"], ...defaults };
这是一些关于对象的基础知识。对象是 TypeScript 中非常重要的数据结构,对于表示数据和组织代码结构都起着关键作用。
函数
基本函数
typescript
function add(x: number, y: number): number {
return x + y;
}
let result: number = add(3, 5);
1. 无参无返函数
javascript
function greet(): void {
console.log("Hello!");
}
greet();
解释: 无参无返函数表示该函数不接受任何参数,也不返回任何值。在上面的例子中,greet
函数用于打印简单的问候语,没有输入参数,也没有返回值。
2. 无参有返函数
typescript
function getRandomNumber(): number {
return Math.random();
}
let randomNum: number = getRandomNumber();
// 无参有返
function fn2(): void {
return undefined;
}
function fn3(): undefined {
return undefined;
}
function fn4(): number {
return 100;
}
function fn5(): string {
return "qf_001";
}
function fn6(): { id: number; name: string } {
return { id: 1, name: "张三" };
}
interface IFn7 {
id: number;
name: string;
}
function fn7(): IFn7 {
return { id: 1, name: "张三" };
}
function fn8(): number[] {
return [1, 2, 3];
}
function fn9(): Array<string> {
return ["1", "2", "3"];
}
解释: 无参有返函数表示该函数不接受任何参数,但会返回一个值。在这个例子中,getRandomNumber
函数返回一个随机数,因此它的类型为 number
。通过调用该函数,可以获得一个随机数并存储在变量 randomNum
中。
3. 有参无返函数
js
function greetPerson(name: string): void {
console.log(`Hello, ${name}!`);
}
greetPerson("John");
// 有参无返
function fn10(a: number, b: string): void {}
解释: 有参无返函数表示该函数接受一个或多个参数,但不返回任何值。在上面的例子中,greetPerson
函数接受一个 name
参数,用于向控制台输出对特定人的问候语。
4. 有参有返函数
js
// 有参有返
function fn11(a: number, b: number): number {
return a + b;
}
// const fn12: number = 100
// const fn12: string = "qf001";
const fn12: (a: number, b: number) => number = function (
a: number,
b: number
): number {
return a + b;
};
const fn13: (a: number, b: number) => void = function (
a: number,
b: number
): void {};
const fn14: () => void = function (): void {};
// 1. 赋值式创建的一个普通函数
// const fn15 = function (a, b) { return a + b }
// 2. 将普通函数改造成 箭头函数
// const fn15 = (a, b) => { return a + b }
// 3. 利用箭头函数的语法, 简化我们的代码
// const fn15 = (a, b) => a + b;
// 4. 给函数的形参添加类型校验
// const fn15 = (a: number, b: number) => a + b;
// 5. 给函数的返回值添加类型校验
// const fn15 = (a: number, b: number): number => a + b;
// 6. 给变量添加一个类型校验
const fn15: (a: number, b: number) => number = (a: number, b: number): number => a + b;
解释: 有参有返函数表示该函数接受一个或多个参数,并返回一个值。在这个例子中,add
函数接受两个参数 x
和 y
,并返回它们的和。通过调用该函数,可以得到两个数字的和,并将结果存储在变量 sum
中。
这四种基本的函数类型展示了函数在 TypeScript 中的常见用法,从简单的问候语到执行数学运算,你可以根据需要选择适当的函数类型。
可选参数和默认参数
- 可选参数:
typescript
function greet(name: string, greeting?: string): string {
if (greeting) {
return `${greeting}, ${name}!`;
} else {
return `Hello, ${name}!`;
}
}
let greeting1: string = greet("John"); // 输出 "Hello, John!"
let greeting2: string = greet("Jane", "Good morning"); // 输出 "Good morning, Jane!"
- 默认参数:
typescript
function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}!`;
}
let result: string = greet("John"); // 输出 "Hello, John!"
接口
接口用于定义对象的结构,提高代码的可读性和可维护性:
ini
interface Person {
name: string;
age: number;
}
let person: Person = { name: "John", age: 30 };
接口合并
- TS 中 允许我们的接口名重复, TS 会将我们两个接口 做一个合并
- 后续属性声明必须属于同一类型
- 所有接口中都可以按照下列的方式添加一个可选的属性, 也就是对象中这个属性可有可无, 但是如果有必须按照接口中指定的数据类型
js
text?: string // 对象中可以没有 text 属性, 但是如果有这个属性, 那么属性值必须是 字符串类型
js
interface IObj {
id: number;
name: string;
}
interface IObj {
// 属性名相同
// id: string // 后续属性声明必须属于同一类型 (此时 id 的属性值, 必须是 number)
id: number
// 属性名不相同
age: number
text?: string // 对象中可以没有 text 属性, 但是如果有这个属性, 那么属性值必须是 字符串类型
}
const obj: IObj = {
id: 1,
name: "张三",
age: 18
};
const obj1: IObj = {
id: 2,
name: '李四',
age: 28,
// text: 'qf001'
// text: 100
// text: true
}
泛型
泛型允许你编写能够适用于不同类型的代码,提高代码的复用性:
js
function identity<T>(arg: T): T {
return arg;
}
let result: string = identity("Hello");
let anotherResult: number = identity(42);
- 需求: 封装一个函数, 接受两个参数, 一个是数组的长度, 一个是数组内填充的内容, 这个函数根据两个形参创建出来一个数组, 然后返回出来
js
// 2. 添加 ts 类型校验
function createArr(length: number, value: any): any[] {
// 根据 形参创建出来一个数组
const arr: any[] = [];
for (let i = 0; i < length; i++) {
arr.push(value);
}
return arr;
}
const arr1 = createArr(3, "数组填充");
console.log(arr1); // ['数组填充', '数组填充', '数组填充']
const arr2 = createArr(5, true);
console.log(arr2); // [true, true, true, true, true]
const arr3 = createArr(2, 10086);
console.log(arr3); // [10086, 10086]
const arr4 = createArr(3, { text: "对象用于填充数组" });
console.log(arr4)
// 3. 利用泛型优化上述代码
function createArr<T>(length: number, value: T): T[] {
// 根据 形参创建出来一个数组
const arr: T[] = [];
for (let i = 0; i < length; i++) {
arr.push(value);
}
return arr;
}
const arr1: string[] = createArr<string>(3, "数组填充");
console.log(arr1); // ['数组填充', '数组填充', '数组填充']
const arr2: boolean[] = createArr<boolean>(5, true);
console.log(arr2); // [true, true, true, true, true]
const arr3: number[] = createArr<number>(2, 10086);
console.log(arr3); // [10086, 10086]
interface IObj {
text: string;
}
const arr4: IObj[] = createArr<IObj>(3, { text: "对象用于填充数组" });
// const arr4: { text: string }[] = createArr<{ text: string }>(3, { text: "对象用于填充数组" });
console.log(arr4);
类型别名(Type)
在 TypeScript 中,类型别名(Type Alias)是一种给一个类型起别名的方式,可以提高代码的可读性和复用性。以下是有关类型别名的基础知识:
1. 基本类型别名
可以使用 type
关键字为基本类型创建别名:
typescript
type ID = number;
type Username = string;
let userId: ID = 1;
let username: Username = "john_doe";
2. 对象类型别名
可以使用类型别名为对象类型创建别名:
typescript
type Point = {
x: number;
y: number;
};
let point: Point = { x: 10, y: 20 };
3. 函数类型别名
可以使用类型别名为函数类型创建别名:
typescript
type AddFunction = (x: number, y: number) => number;
let add: AddFunction = (a, b) => a + b;
4. 泛型类型别名
类型别名也可以使用泛型:
typescript
type Pair<T, U> = {
first: T;
second: U;
};
let pair: Pair<number, string> = { first: 1, second: "two" };
5. 字符串字面量类型别名
使用类型别名可以创建字符串字面量类型:
typescript
type Direction = "left" | "right" | "up" | "down";
let direction: Direction = "left";
6. 类型别名 vs. 接口
类型别名和接口在很多情况下是可以互换使用的,但也有一些区别。通常,当你需要扩展或实现时,使用接口更为合适;而在其他情况下,使用类型别名可能更简洁。
- type 也可以完成 interface 的功能, 两者最大的区别就是 type 需要
=
- 一般在开发的时候, 我们如果是给对象添加类型校验我们会选择 interface
- type 一般更多的是给 字符串使用
- type 内部的属性可以用 换行/逗号/分号
typescript
// 使用接口
interface Person {
name: string;
age: number;
}
// 使用类型别名
type Point = {
x: number;
y: number;
};
类型别名是 TypeScript 中强大而灵活的一部分,它使得我们能够更清晰地定义和组织各种类型。
枚举(Enum)
在 TypeScript 中,枚举(Enum)是一种用于命名一组命名常量的数据类型,使代码更具可读性。以下是有关枚举的基础知识:
1. 枚举基础
使用 enum
关键字定义枚举:
typescript
enum Direction {
Up,
Down,
Left,
Right,
}
默认情况下,枚举的值从 0 开始,依次递增。在上面的例子中,Direction.Up
的值为 0,Direction.Down
的值为 1,以此类推。
2. 指定枚举值
可以为枚举的成员指定具体的值:
typescript
enum Direction {
Up = 1,
Down,
Left = 3,
Right,
}
在这个例子中,Direction.Up
的值为 1,Direction.Down
的值为 2,Direction.Left
的值为 3,Direction.Right
的值为 4。
3. 字符串枚举
枚举的成员可以是字符串:
typescript
enum Day {
Monday = "Monday",
Tuesday = "Tuesday",
Wednesday = "Wednesday",
Thursday = "Thursday",
Friday = "Friday",
Saturday = "Saturday",
Sunday = "Sunday",
}
4. 计算和常量成员
枚举成员可以是计算出来的值或常量值:
typescript
enum FileAccess {
// 常量成员
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write, // 计算成员
}
5. 反向映射
枚举可以通过值反向映射到相应的名称:
typescript
enum Direction {
Up,
Down,
Left,
Right,
}
let directionName: string = Direction[1]; // 得到 "Down"
6. 枚举用法
枚举在代码中的应用场景包括状态表示、选项集合等。例如:
typescript
enum TrafficLight {
Red,
Yellow,
Green,
}
function getTrafficLightMessage(light: TrafficLight): string {
switch (light) {
case TrafficLight.Red:
return "Stop";
case TrafficLight.Yellow:
return "Slow down";
case TrafficLight.Green:
return "Go";
default:
return "Unknown light";
}
}
let message: string = getTrafficLightMessage(TrafficLight.Yellow);
console.log(message); // 输出 "Slow down"
枚举提供了一种更具可读性的方式来表示一组常量,并且在一些场景中能够更好地反映代码的意图。
类
类是面向对象编程的基础,TypeScript 支持类和继承:
scala
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): void {
console.log("Some generic sound");
}
}
class Dog extends Animal {
makeSound(): void {
console.log("Bark");
}
}
let myDog: Dog = new Dog("Buddy");
myDog.makeSound(); // 输出 "Bark"
模块
TypeScript 支持模块化开发,可以使用 import
和 export
关键字:
typescript
// math.ts
export function add(x: number, y: number): number {
return x + y;
}
// app.ts
import { add } from "./math";
let result: number = add(3, 5);
类型断言
类型断言用于告诉编译器变量的实际类型,类似于类型转换:
ini
let value: any = "Hello, TypeScript!";
let strLength: number = (value as string).length;
这只是 TypeScript 的基础知识,它还有更多高级特性和功能,可以根据项目需求深入学习。