背景
Typescript 是一种由微软开发的自由与开源的编程语言。
TypeScript 设计目标是开发大型应用,然后转译成 JavaScript。
由于 TypeScript 是 JavaScript 的严格超集,任何现有的 JavaScript 程序都是合法的 TypeScript 程序。
目前有很多大型开源项目都开始使用 TypeScript,例如:Vue 3.0、React 周边、Angluar、Vscode、AntDesign、Taro 等。
安装
npm
首先,在命令行运行 npm install -g typescript 命令全局安装 typescript;
其次,在命令行通过 tsc 命令执行 typescript 相关文件;
举例:新建一个 test.ts 文件,通过在命令行运行 tsc test.ts,同一个目录下会生成一个 test.js 文件。
tsc test.ts
编辑器
例如:Vscode、sublime、webstorm 等,都有 TypeScript 插件;
通过这些 IDE 即可自动解析 .ts 文件。
用法
基础类型
- Boolean(布尔值)
- Number(数字)
- String(字符串)
- Null 与 undefined
- Object(除 boolean、number、string、symbol、undefined、null 的类型)
- Any(任何类型)
- Void(没有任何类型,通常表示无返回值的函数)
- Never(永远不存在的值类型,是任何类型的子类型,应用场景:无限循环 & 抛出异常)
- Array (数组)
- 元组(已知类型和数量的数组)
- 枚举(对标准数据的类型的补充)
// 布尔值const sign: boolean = true;// 数字const age: number = 6;// 字符串const str: string = 'DR';// undefined、nullconst a: undefined = undefined;const b: null = null;// objectconst obj: object = {};// anyconst age: any = '18';// voidfunction eat(): void {}// neverfunction drink(): never { while(true) {}; }function drink(): never { throw new Error(''); }// 数组const list: number[] = [1, 2, 3];const list: Array<number> = [1, 2, 3];// 元组const list: [number, string] = [1, 'DR'];// 枚举enum Step = { One, Two, Three }; // One = 0, Two = 1, Three = 2enum Step = { One = 1, Two, Three }; // One = 1, Two = 2, Three = 3
类型断言
可以用来手动指定一个值的类型;
存在两种语法:<类型>值(
// 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候// 我们只能访问此联合类型的共有属性或者方法,否则会出现报错// 可以getLen = (something: string|number) => {return something.toString();}// 报错getLen = (something: string|number) => {return something.length;}// 解法,在某些场景下将 something 断言成 stringgetLen = (something: string|number) => {if ((<string>something).length) {return (<string>something).length;} else {return something.toString().length;}}
接口
接口是一种规范的定义,它定义了行为和动作的规范,接口起到一种限制和规范的作用;
枚举下接口包含的几种类型:
- 属性类型接口
- 函数类型接口
- 可索引类型接口
- 类类型接口
属性类型接口
对对象进行约束,对象的 Key 与 Value 要遵守接口所声明的内容;
其中包含:正常属性,可选属性、只读属性等一些特殊内容; ```typescript interface People { name: string; age?: number; // 可选属性 readonly sex: string; // 只读属性 };
const people: People = { name: ‘段然’ // 生命属性,一定要有 age: 18, // 可选属性,可有可无 sex: ‘男’ // 只读属性 };
people.sex = ‘女’; // 错误,只读属性不能修改 console.log(people.sex) // 正确
<a name="2Wa34"></a>### 函数类型接口对方法传入的参数以及返回值进行约束,函数的参数与返回值要遵守接口所声明的内容;```typescriptinterface People {(name: string, age: number): string;}const people: People = (name: string, age: number): string => name + age;people('段然', 18); // 正确people('段然', '18'); // 错误
可索引类型接口
对数组和对象进行约束(不常用),数组或者对象的索引(数组即下标、对象即 Key)与内容要遵守接口所声明的内容;
interface Obj {[index: string]: string;};interface Arr {[index: number]: number;};const arr1: Arr = [1, 2, 3] // 正确const arr2: Arr = ['1', '2', '3'] // 错误const obj1: Obj = { '1': '1' } // 正确const obj2: Obj = { '1': 1 } // 错误const obj3: Obj = { 1: 1 } // 错误
类类型接口
对类进行约束,类需要去实现接口中的方法与属性,类的实现要遵守接口所声明的内容;
interface Animal {name: string;eat(): void;};class Dog implements Animal {name: string;constructor() {this.name = 'dog'}eat(): void {}};const dog = new Dog(); // 正确
接口间的继承
接口之间也可以相互继承,如果继承多个接口通过 “,” 分割;
interface A {name: string;};interface B {age: number;};inferface C extends A { // 包含 name: string 与 sex: stringsex: string;};inferface D extends A, B { // 包含 name: string、age: number 与 sex: stringsex: string;};
混合类型接口
混合类型的接口可以混合属性类型接口与函数类型接口;
interface Person {(name: string, age: number): string; // 函数类型接口;eat(): void; // 属性类型接口}function person: Person {// 函数类型接口应用const p: Person = (name: string, age: number): string => name + age;// 属性类型接口p.eat = () => {};return p;}const p = person();p('段然', 18); // 正确p.eat(); // 正确
接口继承类
接口继承了一个类时,它会继承类的成员但不包括其实现(会继承到类的 private、protected、public 成员);
class A {name: string;constructor() {this.name = '段然';}}interface B extends A {age: number;} // 此时 B 接口中存在 name: string 与 age: number 两个属性class C implements B {name: string;age: number;constructor() {// 类 C 必须要实现接口 B 包含的成员(name 与 age)this.name = '段然';this.age = 18;}}class D extends A implements B {age: number;constructor() {// 类 D 必须要实现接口 B 包含的成员(name 与 age)// 但由于继承自 A,已经包含了 name,只实现 age 即可this.age = 18;}}
类
公共、受保护与私有修饰符
- public 公共修饰符,Typescript 中默认为 public
- 类的实例可使用类中的方法与属性
- 派生的类可使用类中的方法与属性 ```javascript class A { public name: string; public constructor(): void { this.name = ‘段然’ } public say(): void { console.log(this.name); } }
class B extends A { constructor(props) { super(props); this.say(); // 正确 } }
const a = new A(); a.name = ‘段然然’; // 正确 a.say(); // 正确
- protected 受保护修饰符- 类的实例不可使用类中的方法与属性- 派生的类可使用类中的方法与属性```javascriptclass A {protected name: string;protected constructor(): void {this.name = '段然'}protected say(): void {console.log(this.name);}}class B extends A {constructor(props) {super(props);this.say(); // 正确}}const a = new A();a.name = '段然然'; // 错误,类的实例不可使用类中的方法与属性a.say(); // 错误,类的实例不可使用类中的方法与属性
- private 私有修饰符
- 类的实例不可使用类中的方法与属性
- 派生的类不可使用类中的方法与属性 ```javascript class A { private name: string; private constructor(): void { this.name = ‘段然’ } private say(): void { console.log(this.name); } }
class B extends A { constructor(props) { super(props); this.say(); // 错误,派生的类不可使用类中的方法与属性 } }
const a = new A(); a.name = ‘段然然’; // 错误,类的实例不可使用类中的方法与属性 a.say(); // 错误,类的实例不可使用类中的方法与属性
<a name="LHNn7"></a>### 只读属性通过 readonly 修饰符可以设置类的属性为只读属性;```javascriptclass A {public readonly name: string;public constructor(): void {this.name = '段然'}}const a = new A();a.name = '段然然'; // 报错,属性只读,不可修改console.log(a.name) // 正确
静态属性
通过 static 修饰符可以设置属性与方法为静态属性,static 设置的属性与方法是挂载在类上面的,类的实例上是不存在此属性与方法的;
class A {static name = '段然';static say () {console.log(A.name);}};console.log(A.name); // 正确A.say(); // 正确
抽象类
抽象类可以做为其它派生类的基类使用,它们不可以被实例化;
abstract class A {public readonly name: string;public constructor(): void {this.name = '段然'}}class B extends A {} // 正确const a = new A(); // 报错
函数
为函数定义类型
Typescript 中的函数可以定义参数类型与返回类型;
function people (name: string): void {}people('段然'); // 接收的参数是字符串,无返回值
函数中的可选参数
在 TypeScript 里每个参数都是可选的,可传可不传;
function people (name: string, age?: number): void {}people('段然'); // 正确,第二个参数可不传people('段然', 1); // 正确people('段然', '1'); // 错误,第二个参数类型传递错误
函数中的剩余参数
在 TypeScript 里可以把剩余的所有参数收集到一个变量里,达到可扩展的目的;
function people (name: string, ...hobby: string[]): void {}people('段然'); // 正确people('段然', '1', '2'); // 正确people('段然', 1, 2); // 错误,剩余的参数类型传递错误
any 与 unknown
泛型
泛型存在的关键目的是在成员之间提供可扩展性的约束,这些成员可以是:函数参数、函数返回值、接口、类的成员与类的方法等,一句话总结就是:将原本在声明时的约束移动至使用时;
泛型函数
对函数的参数与返回值进行约束;
function eat<T> (food1: T, food2: T): T { return food1 + food2; }eat<string>('meat', 'agg'); // 使用时传递真实类型eat<number>(1, 2); // 使用时传递真实类型
泛型接口
对接口进行约束;
interface People<T> {name: T;};function people<T> (name: T): People<T> {return { name };}people<string>('段然'); // 使用时传递真实类型
泛型类
对类中的成员变量与方法进行约束;
class People<T> {name: Tconstructor(name: T) {this.name = name;}say(): T {return this.name;}};const people = new People<string>('段然'); // 使用时传递真实类型const people = new People<number>(111); // 使用时传递真实类型
泛型参数的约束
对泛型的参数进行一些约束;
function eat<T extends Length> (food1: T, food2: T): T { return food1 + food2; }eat<string>('meat', 'egg'); // 正确eat<number>(1, 2); // 错误,只有含有 length 的参数才可以被传入;
泛型传递多个参数
泛型中可以传递多个参数,通过 “,” 进行分割;
function eat<A, B> (food1: A, food2: B): A { return food1; }eat<string, number>('meat', 1);
泛型设置默认参数
泛型可以设置默认类型的参数;
function eat<T = string> (food1: T, food2: T): T { return food1 + food2; }eat('meat', 'egg');
