TypeScript快速入门
TypeScript 快速入门
TypeScript 简称 TS, 是JS(JavaScript)的超集,TS编译器会把TS代码编译成JS代码;为微软家开发的;
安装
全局安装`sudo npm i -g typescript`
安装好后输入命令`tsc -v`可以查看输出结果
编译,输入`tsc index.ts`, 会将index.ts文件转编译成index.js文件
初始化配置文件
首先需要创建一个项目文件夹,在命令行中`cd`到文件夹后执行`tsc --init`, tsc就会在文件夹中创建一个默认的TS配置文件`tsconfig.json`,刚开始建议可以修改以下的值:
{
"target": "ES2016",
"rootDir": "./src", // 将源码默认存放的文件夹放到src目录下
"outDir": "./dist", // 将编译后生成的代码放到dist目录下
"noEmitOnError": true, // 编译出错后不继续编译
"sourceMap": true, // 编译后生成一个sourceMap文件,开发的时候方便浏览器调试,生产环境可以关掉
... ...
}
有了`tsconfig.json`文件后直接输入`tsc`命令后就会按照配置进行编译项目
类型
TS变量标记类型的方式:
let t: number; // 不含初始值
const x: string = '含初始化值';
const a: number[] = [1, 2, 3]; // 数组
// 如果没有给变量标记类型,TS默认有类型推断的功能
const q = 123; // number
JS有6种类型, TS有5种新增类型:
JS | 注意 | TS | |||
---|---|---|---|---|---|
number | 数字 | ts中的nubmer类型可以用下划线分隔, | any | 任意 | |
string | 字符串 | unknown | 未知 | ||
boolean | 布尔 | never | |||
null | 空 | enum | 枚举 | ||
undefined | 未定义 | tuple | 元组 | ||
objects | 对象 |
any、unknown、never的使用区别
any:这个类型是 TypeScript 的超级类型(也可以说是 "万能" 类型)。如果声明一个值为 any 类型,那么可以对它进行任何操作,而不会看到类型错误,这个类型一般不能随意使用,因为其实它就是回归了JS的用法。
unknown:这个类型是 TypeScript 的安全类型版本的 any。如果声明一个值为 unknown 类型,那么不能对它进行任何操作,除非先进行类型检查或类型断言。例如:
let unknownThing: unknown = 'hello';
unknownThing = 42;
unknownThing.foo.bar; // 会报错
if (typeof unknownThing === 'object' && unknownThing != null) {
unknownThing.foo.bar; // 不会报错,因为已进行了类型检查
}
never:这个类型表示永远不会有值的类型。例如,函数如果永远抛出错误或者永远循环,那么它的返回类型就是 never。
function alwaysThrows(): never {
throw new Error('Always throws');
}
function infiniteLoop(): never {
while (true) {}
}
数组
在TS中,有两种定义数组的方式:
类型 + []
let numberArray: number[] = [1, 2, 3];
let stringArray: string[] = ['hello', 'world'];
Array<elemType>
let numberArray: Array<number> = [1, 2, 3];
let stringArray: Array<string> = ['hello', 'world'];
let arrayArray: Array<number[]> = [[1], [2, 3]];
ts中有一种称为元组的特殊数组⬇️
元组(Tuple)
元组是一个已知元素数量和类型的数组,各元素的类型不必相同。
const x: [string, number] = ['s', 12]
枚举(enum)
enum Size {
Small,
Medium,
Large,
Error = -1
}
const myClothSize: Size = Size.Large
函数(function)
在 TypeScript 中,函数的类型由参数类型和返回值类型组成。函数默认返回一个`undefined`类型,并且会自动推断函数返回值:
function greet(name: string): string {
return 'Hello, ' + name;
}
function greet1(name: string) { // 自动推断类型为string
return 'Hello1, ' + name;
}
function print(name?: string): void { // ?: 表示参数可选
if (name) {
console.log('Hello, ' + name);
} else {
console.log('Hello, Guest');
}
}
function greet2(name: string = 'Guest'): string { // = 表示参数有默认值,参数亦可选
return 'Hello, ' + name;
}
TS函数检查配置
在`tsconfig.json`文件中可以设置以下几个值对函数进行规范检查:
{
...
"noUnusedLocals": true, // 没有用到的函数变量会被警告
"noUnusedParameters": true, // 函数参数没有被用到就会引发错误
}
函数重载
TS函数支持函数重载:
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
if (typeof a === 'string' && typeof b === 'string') {
return a + b; // 字符串拼接
} else if (typeof a === 'number' && typeof b === 'number') {
return a + b; // 数值相加
}
}
objects
在 TypeScript 中,你可以使用接口(`interface`)或类型别名(`type`)来描述一个对象的形状(shape)。
1. 接口 interface
接口是定义对象的一个强有力的方式。可以定义必需的属性、可选的属性,以及索引签名等。例如:
interface Person {
firstName: string;
lastName: string;
age?: number; // 可选属性
[propName: string]: any; // 索引签名
}
let john: Person = {
firstName: 'John',
lastName: 'Doe',
age: 27,
address: '123 Main St' // 任意额外属性都是允许的,因为有索引签名
};
2. 类型别名 type
类型别名也可以用来描述一个对象的形状,且可以表示更复杂的类型形状:
type Person = {
firstName: string;
lastName: string;
age?: number;
}
let jane: Person = {
firstName: 'Jane',
lastName: 'Doe',
age: 25
};
接口和类型别名在大多数情况下可以互换使用,但它们有一些微妙的差别。例如,接口可以被声明合并(同名接口在编译时会被合并为一个接口),而类型别名不能。相反,类型别名可以表示一些接口不能表示的类型,例如联合类型。
此外,TypeScript 还支持类(`class`)和字面量对象(literal object),这些都可以用来创建和使用对象。例如:
class Car {
make: string;
model: string;
constructor(make: string, model: string) {
this.make = make;
this.model = model;
}
drive() {
console.log(`Driving a ${this.make} ${this.model}`);
}
}
let myCar = new Car('Toyota', 'Corolla');
myCar.drive();
let myObject = {
prop1: 'Hello',
prop2: 42
};
3. 接口和别名的区别
接口可以被重复声明,重复的声明会被合并;
接口可以被类实现(implements)
接口只能用来描述对象的形状(包括函数和构造签名)
类型别名不能被声明合并。声明一个类型别名会报错。
类型别名也可以使用 typeof 关键字来获取一个值的类型。
类型别名可以表示一些接口不能表示的类型形状,例如原始类型(如 string,number),元组,和联合类型。
联合类型 Union Types
联合类型是一种复合类型,表示一个值可以是几种类型之一, 用 |管道符
表示。
let myVar: string | number;
myVar = 'Hello'; // OK
myVar = 42; // OK
myVar = true; // Error:
function processValue(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase();
} else {
return value.toFixed(2);
}
}
交叉类型 Intersection Types
交叉类型是一种复合类型,表示一个值同时具备多种类型的特性。你可以通过 & 与
操作符将多个类型组合成一个交叉类型。
interface CanWalk {
walk: () => void;
}
interface CanSwim {
swim: () => void;
}
type Amphibian = CanWalk & CanSwim;
let frog: Amphibian = {
walk: () => console.log('Walking'),
swim: () => console.log('Swimming')
};
字面量类型 Literal Types
字面量类型和枚举(enum)在某些场景下可以起到类似的作用
type Easing = "ease-in" | "ease-out" | "ease-in-out"; // 字符串字面量类型
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6; // 数字字面量类型
type TrueOnly = true; // 布尔字面量类型 不常用
Nullable TypesNullable Types
Nullable Types
在 TypeScript默认情况中,null 和 undefined 是所有其他类型的子类型,这意味着可以将 null 和 undefined 赋值给任何类型的变量。
在 tsconfig.json
文件中设置 "strictNullChecks": true
可以改变上面的默认行为,启用 strictNullChecks
之后,null 和 undefined 就只能被赋值给它们各自和 void 的类型,如果想让其他类型的变量能被赋值 null 或 undefined,你就需要使用联合类型。
let s: string; // OK
s = null; // Error when strictNullChecks is true
let sn: string | null; // OK
sn = null; // OK
sn = "abc"; // OK
映射类型 Mapped types
从一个已知的类型生成新的类型,主要的功能就是通过一个已知的类型 T,生成一个新的类型,其中 T 中的每个属性都会进行某种形式的转换。
改变属性的可选性:比如 Partial<T> 和 Required<T>,它们分别可以将 T 中的所有属性变为可选的或必须的。
type Partial<T> = {
[P in keyof T]?: T[P]; // ? 表示添加可选性
};
type Required<T> = {
[P in keyof T]-?: T[P]; // -? 表示去除可选性
};
添加 readonly 修饰符:比如 Readonly<T>,它可以将 T 中的所有属性变为只读的。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
将属性的值的类型进行转换:自定义映射类型,将属性的值的类型进行转换。
type Stringify<T> = {
[P in keyof T]: string;
};
条件类型 Conditional types
允许一个类型表达式根据一个条件选择两种可能的类型之一。通过 T extends U ? X : Y
的形式实现。
type IfArray<T> = T extends Array<any> ? T[number] : T;
type A = IfArray<string>; // string
type B = IfArray<string[]>; // string
// 在这个例子中,IfArray<T> 是一个条件类型,它根据类型 T 是否可以赋值给 Array<any> 来选择不同的类型。如果 T 可以赋值给 Array<any>,那,也么结果类型就是 T[number]就是数组的元素类型;否则结果类型就是 T。
直接看例子:
提取函数的返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
function f() {
return { a: 1, b: 2 };
}
type R = ReturnType<typeof f>; // { a: number; b: number; }
判断一个类型是否是数组
type IsArray<T> = T extends Array<any> ? true : false;
type A = IsArray<number[]>; // true
type B = IsArray<number>; // false
提取 Promise 的结果类型
type PromiseType<T> = T extends Promise<infer U> ? U : T;
async function g() {
return { a: 1, b: 2 };
}
type P = PromiseType<ReturnType<typeof g>>; // { a: number; b: number; }
TS 中的面向对象
在 TypeScript 中,可以使用类(class)、接口(interface)、继承(inheritance)、封装(encapsulation)等概念来实现面向对象编程。
类 class
类(Class): 类是面向对象编程的核心,它定义了一件事物的抽象特点。类定义了事物的属性(fields)和方法(methods)。
class Car {
color: string;
constructor(color: string) {
this.color = color;
}
drive() {
console.log('Driving...');
}
}
对象 Object
类的实例被称为对象。可以使用 new
关键字创建一个新的对象实例。
继承 Inheritance
class Tesla extends Car {
autopilot: boolean;
constructor(color: string, autopilot: boolean) {
super(color); // call the constructor of the base class
this.autopilot = autopilot;
}
selfDrive() {
if (this.autopilot) {
console.log('Self-driving...');
}
}
}
let myTesla = new Tesla('white', true);
myTesla.selfDrive();
封装 Encapsulation
可以使用 private、protected 和 public
访问修饰符来实现封装
public: 公开修饰(默认),类外部可以访问
privite: 私有修饰,只有类内部被允许访问
protected:保护修饰,类内部和派生类可以访问
接口 Interface
接口在 TypeScript 中是一个非常重要的概念。接口定义了代码中对象的类型,描述了对象的形状和方法
interface Drivable {
drive(): void;
}
class Car implements Drivable { // 实现
drive() {
console.log('Driving...');
}
}
声明文件
// index.d.ts
declare function myFunction(a: string, b: number): void;
... 等我研究一下
#前端(1)评论