这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
TypeScript
TypeScript 是 JavaScript 的一种超集,它在 JavaScript 的基础上添加了静态类型和类型推断的概念。这使得程序员能够在编写代码时更早地发现错误,并且可以提高代码的可读性和可维护性。
TypeScript 提供了与类似于 C# 和 Java 的面向对象编程语言类似的语法,如类和接口。这样可以使用面向对象的方式来组织 JavaScript 代码,使其更具结构性和可维护性。
同时 TypeScript 也支持模块化编程,可以在编译时检查模块之间的依赖关系,提高代码的稳定性。
静态语言和动态语言是指编程语言的类型。
静态语言在编译时就已经确定了变量的类型,变量的类型在运行时是不可变的。常见的静态语言有C、C++、Java。
动态语言则不同,变量的类型是在运行时确定的,变量的类型可以在运行时改变。常见的动态语言有Python、JavaScript、Ruby。
区别就在于静态语言需要在编译时类型检查,会增加编译时间但会减少运行时错误,而动态语言在运行时进行类型检查,编译时间短但会增加运行时错误。
TypeScript中的泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而是在使用时再指定类型的一种特性。这样做可以让一个函数、接口或类可以支持多种类型的数据,而不必对每种类型都进行重新定义。 例如,我们可以定义一个泛型函数identity,它可以接受任何类型的参数并返回相同类型的值:
function identity<T>(arg: T): T {
return arg;
}
在使用时,我们可以指定identity函数的类型参数,例如:
let output = identity<string>("myString"); // type of output will be 'string'
也可以让编译器自动推断类型
let output = identity("myString"); // type
类型别名&类型断言
类型别名是在 TypeScript 中定义一个新名称来引用一个已有类型。 它可以使代码更具可读性,并且可以用来给复杂的类型起一个简短的名字。 例如:
type Name = string;
type Age = number;
type Person = { name: Name, age: Age }
类型断言是在 TypeScript 中手动指定一个值的类型。 它可以让你告诉编译器一个值的类型,而不是让编译器自动推断。 例如:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
这两个断言方式是等价的
总结:
基本语法包括:
类型注解: 在变量名之前使用冒号来声明变量的类型,如:
let myName: string = 'John Doe';
函数参数类型: 在函数定义时使用冒号来声明参数的类型,如:
function add(a: number, b: number): number { return a + b; }
接口: 使用 interface 关键字来定义一个接口,可以用来约束对象的类型,如:
interface Person { name: string; age: number; }
类: 使用 class 关键字来定义一个类,支持继承、接口实现、访问修饰符等特性,如:
class Employee { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } }
泛型: 使用泛型来支持多种类型的参数或者返回值,如:
function identity<T>(arg: T): T { return arg; }
类型别名: 使用 type 关键字来给一种类型起个新名字,如:
type Name = string;
let myName: Name = 'John Doe';
类型断言: 使用尖括号或者as关键字,告诉编译器一个值的类型,如:
let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;
let strLength2: number = (someValue as string).length;
TypeScript高级数据类型
联合/交叉类型
在 TypeScript 中,联合类型表示一个值可以是多种类型之一。它可以使用竖线(|)来表示。例如:
let value: string | number;
value = "hello";
value = 42;
上面代码定义了一个变量 value,它可以是字符串类型或者数字类型。访问联合类型时,处于程序安全,仅能访问交集部分
而交叉类型则是将多个类型合并在一起。它可以使用 & 符号来表示。例如:
interface A { a: string; }
interface B { b: number; }
let value: A & B;
value = { a: 'hello', b: 42 };
上面代码定义了一个变量 value, 它同时具有 A 和 B 两个接口的属性。
这种方式使用在需要同时保证多个类型的情况, 比如类型检查或者函数传参
类型保护与类型守卫
类型保护是指在程序运行时使用特定的判断条件来确定一个变量的类型。在 TypeScript 中,可以使用 typeof、instanceof 以及 in 运算符来实现类型保护。
类型守卫是指在类型保护条件成立时,编译器会知道一些关于变量类型的额外信息,这些信息可以被用来缩小变量类型的范围。类型守卫可以通过自定义的类型保护函数来实现。
类型保护是 TypeScript 中的一种机制,它可以在编译时进行类型检查,这样就可以在编码阶段就发现一些类型错误,提高了代码的健壮性。类型守卫可以在编译器确定了变量类型的基础上,对变量的使用进行限制,避免出现运行时错误。
TypeScript 中高级类型包括了联合类型、交叉类型、类型保护、类型守卫、类型别名、类型断言、泛型等。
联合类型(Union Types)是指一个变量可能具有多种类型之一,使用 "|" 进行声明。
交叉类型(Intersection Types)是指将多个类型合并为一个类型,使用 "&" 进行声明。
类型保护(Type Guard)是指在程序中使用特定的判断来确定一个变量的类型,常见的实现方式有 typeof 和 instanceof。
类型守卫(Type Guard Functions)是指为了确定一个变量的类型而定义的函数。
类型别名(Type Alias)是指为一个类型起一个新的名字。
类型断言(Type Assertion)是指手动指定一个值的类型。
泛型(Generics)是指在定义函数、接口或类时,不预先指定具体的类型,而在使用时再指定类型的一种特性。
在 TypeScript 中,函数返回值类型可以明确地指定为函数定义时的返回值类型。
例如,下面是一个返回字符串类型的函数的示例:
function getName(): string {
return 'John Doe';
}
另一个示例是返回数组的函数:
function getNumbers(): number[] {
return [1, 2, 3];
}
在上面的例子中,函数名后面的冒号和类型指定了函数的返回值类型。如果函数在运行时返回了不同类型的值,则编译器会发出错误。
需要注意的是,如果函数存在多种返回情况,则需要使用联合类型来指定可能的返回类型。
function getData(): string | number {
if (someCondition) {
return 'hello';
}
return 42;
}
上面这个函数可能返回字符串或数字,因此我们使用联合类型 string | number 来指定可能的返回类型。
Marge函数类型实现
可以使用类型断言和类型保护来实现合并两个不同类型的函数。
例如,我们有两个函数,一个函数接受一个数字参数并返回字符串,另一个函数接受一个字符串参数并返回数字,我们可以使用如下代码来合并这两个函数:
function merge<A, B, C>(
func1: (a: A) => B,
func2: (b: B) => C
): (a: A) => C {
return (a: A) => func2(func1(a));
}
上面的代码中,我们使用了泛型来指定函数的参数和返回值类型。函数 merge 接受两个函数作为参数,并返回一个新的函数。新的函数接受一个参数 a,并将其传递给 func1,然后将 func1 的返回值传递给 func2,最后返回 func2 的返回值。
我们可以使用下面的方式来使用这个 merge 函数:
const func1 = (n: number) => n.toString();
const func2 = (s: string) => parseInt(s);
const func3 = merge(func1, func2);
console.log(func3(123)); // output: 123
这样我们就得到了一个新的函数 func3, 它接受一个数字参数并返回一个数字。 func3 通过调用 func1 将数字转换为字符串,再调用 func2 将字符串转换回数字。
工程应用
webpack
1、配置webapack loader相关配置,这里是指在webpack的配置文件中,配置对于不同类型文件的处理方式。比如对于.ts文件,我们需要配置ts-loader来处理这类文件。
2、配置tsconfig.js文件,这是TypeScript项目的配置文件,里面包含了项目编译的相关设置,如编译目标版本、类型声明文件等等。
3、运行webpack启动/打包,在配置完成之后,运行webpack命令,根据配置文件进行打包。
4、loader处理ts文件时,会进行编译与类型检查。当我们使用TypeScript编写项目时,需要使用ts-loader将其编译成javascript,并在编译过程中进行类型检查,以确保代码的正确性。
Node
TSC编译
使用 TSC 编译是将 TypeScript 代码编译成 JavaScript 的过程。
安装 Node 和 npm:Node.js 是 JavaScript 的运行环境,npm 是 Node.js 的包管理器。安装完 Node 和 npm 之后就可以使用 npm 命令来管理项目依赖了。
配置tsconfig.js文件:tsconfig.js 文件是 TypeScript 的配置文件,里面记录了编译选项,包括输出目录、编译选项等。
使用 npm 安装 tsc:TypeScript 编译器是 tsc,需要使用 npm 安装。
使用 tsc 运行编译得到 js 文件:在命令行中运行 tsc 命令,会根据 tsconfig.js 文件中的配置编译 TypeScript 文件,并将编译后的 JavaScript 文件输出到指定目录中。