typescript 文档
TypeScript 要点知识整理
本篇主要是整理一下 typescript 相关的知识点。
什么是 TypeScript
TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持。
安装 TypeScript 及编译 Ts 文件
npm -g install typescrip // 全局安装 typescript
全局安装 typescript 后即可在终端使用 tsc 命令了,编译 ts 文件命令如下:
// hello.ts
function foo(name: string) {
console.log(`Hello ${name}`);
}
foo('Cooper') // Hello Cooper
// terminal
tsc hello.ts // 编译 ts 文件后生成对应的 hello.js 文件
TypeScript 的类型检查说明
Ts 只会进行静态类型检查,如果发现错误,编译的时候就会报错。日常一般搭配 Eslint 或 Tslint 使用,在编码过程中即会报出对应错误。
基本数据类型
通过在变量后加 :类型 声明变量的类型。
1. bolean 布尔值
let isSuccess: boolean = true; // 正确
let isSuccess: boolean = new Boolean(1); // 错误,new 产生的是一个Boolean类型的对象,类型为 Boolean,是一个构造函数,不同于基本数据类型 boolean
let isSuccess: Boolean = new Boolean(1); // 正确
let isSuccess: boolean = Bealean(1); // 返回的仍是一个基本boolean类型的值
说明: 在 typescript 中,boolean 是基本数据类型,而 Boolean 是一个构造函数,定义为 boolean 的值不能是 Boolean 对象。其他基本数据类型亦如此
2. 数字
let num: number = 3; // 正确
num = "3"; // 报错,申明了变量为 number 类型,怎么能赋 string 类型的值呀!
3. 字符串
let name: string = "Cooper";
let templetStr: string = `Hello, ${name}`; // es6 模版字符串
4. 空值
JavaScript 中没有空值(Void)的概念,在 TypeScript 中空值一般用来表示一个函数没有返回值
// 定义一个没有返回值的返回的函数
function foo(name: string): void {
console.log(name);
}
5. Null 和 Undefined
定义为 null 类型的变量只能被赋值为 null, 定义为 undefined 的变量只能被赋值为 undefined
let u: undefined = undefined;
let m: null = null;
任意值
定义为任意值的变量可以被赋值为任意类型。在任意类型的变量上访问任意属性和方法都是可以的。声明一个变量为 any 类型后,对其进行任意操作返回的都是 any 类型。未声明类型的变量默认为 any 类型。
let anyValue: any = "123";
anyValue = 1; // 不会报错,因为 anyValue 的类型为任意值
注意:any 用起来虽然特别方便,但是建议日常开发能不用就不用,毕竟 TypeScript 是为了更规范的书写 Js 代码,如果全部都定义成 any 类型,那就失去了 TypeScript 的意义。
类型推论
如果没有明确的指明某个变量的类型, 那么 TypeScript 会依照类型推论的规则推导出一个类型。
let str = "Cooper";
str = 7; // 报错,根据类型推论确认 str 为 string 类型,则不可以赋 string 外的值
联合属性
联合类型表示取值可以为多种类型中的一种,各个类型间使用分隔线 | 连接
let strOrNumValue: string | number = "test";
- 访问联合类型的属性和方法 当一个变量定义为联合类型,我们只能访问联合类型的公共方法和属性
function getLength(something: string | number) {
return something.length; // 报错,number 类型不包含 length 属性
}
function myToString(something: string | number) {
return something.toString(); // 正确,number 和 string 类型都包含 toString 方法
}
- 联合类型的变量在被赋值后,会根据类型推论的规则推导出一个类型
let something: string | number;
something = "Cooper";
console.log(something.length); // 5, something 赋值字符串后,被推导为 string 类型,因而可以访问 length 属性
something = 3;
console.log(something.length); // 报错
对象的类型 - 接口
在 TypeScript 中,我们用接口来定义对象的类型,接口命名,一般以大写字母 I 开头,且 I 后面的首个字母一并大写,了解 Java 的同学应该很熟悉,这与 Java 是一致的。
interface IPerson {
name: string;
age: number;
}
// 接口的所有属性都需要包含,且各个属性类型一致,否则报错
let Cooper: IPerson = {
name: "Cooper",
age: 23,
};
- 可选属性
用来表示某个对象中的属性是可选的。
interface IPerson {
name: string;
age?: number; // 我们在属性后使用 ? 后表示该属性为可选属性
}
// 可只包含 name 属性,age 为可选属性,可不定义,但是不能添加接口未定义属性
let Cooper: IPerson = {
name: "Cooper",
};
- 任意属性
interface IPerson {
name: string;
age?: string;
[propName: string]: string;
}
let cooper: IPerson = {
// true
name: "Cooper",
gender: "male", // 添加的任意属性 gender
};
注意:一旦定义了任意类型,那么确认属性和可选的属性的类型必须是任意属性类型的子类,举个例子,以上定义改为
// 报错,任意属性为 string,不包括可选属性的 number 类型
interface IPerson {
name: string;
age?: number;
[propName: string]: string;
}
// 应改为以下形式
interface IPerson {
name: string;
age?: number;
[propName: string]: string | number; // 上面定义的具体类型也应包含在任意类型
}
- 只读属性 有时候我们希望有些属性只能在初始化时被赋值,后续不允许修改,则可以使用 readonly 关键字来定义
interface IPerson {
readonly id: number;
name: string;
}
let cooper: IPerson = {
id: 14202119,
name: "Cooper",
};
cooper.id = 14020120; // 报错,只读属性不允许再次修改值
数组的类型定义
在 TypeScript 中数组可以使用多种方式定义类型。
- 类型 + 中括号
let list: number[] = [1, 2, 3]; // 数组中的每一项都 number 类型
- 数组泛型,Array[T], T 为泛型
let list: Array<number> = [1, 2, 3];
- 用接口表示
// key 为 number 类型,即数组下标,值为 number 类型,即 value
interface INumberArray {
[index: number]: number;
}
let list: INumberArray = [1, 2, 3];
- 对象数组的定义
interface IItem = {
name: string,
age: number
}
// 数组中是一个对象,且对象中属性需和定义的一致
let list: IItem[] = [
{
name: 'Cooper',
age: 23
},
{
name: 'Bob',
age: 23
},
]
函数类型
- 函数的声明方式
// 函数式声明
function foo(name) {
console.log(name);
}
// 函数表达式
const mySun = function (x, y) {
return x + y;
};
- 函数式声明定义类型
// 接收两个 number 的参数,不允许少传或多传参数,且函数的返回值必须为 number 类型
function(x: number, y: number): number {
return x + y;
}
- 函数表达式定义类型
let myFun: (x: number, y: number) => number = function (
x: number,
y: number
): number {
return x + y;
};
// 左侧变量的类型可省略,等号左边会根据类型推论推断出来,即:
let myfun = function (x: number, y: number): number {
return x + y;
};
- 使用接口定义
interface IMyFun {
(x: number, y: number): boolean;
}
let myFun: IMyFun = function (x: number, y: number): boolean {
return false;
};
- 可选参数和剩余参数
// y 为可选参数
function myFun(x: number, y?: number): number {
if (y) {
return x + y;
}
}
// 剩余参数
function myFun(x: number, ...ars: any[]) {
console.log(args);
}
myFun(1, 2, "3"); // [2, '3']
类型断言
类型断言即手动(或者说是强制?。?)指定一个变量的类型
-
语法
<类型>变量
变量 as 类型 // tsx 中仅支持此种方式
function myFun(x: number | string) {
console.log(<string>x.length); // 此处变量 x 的属性为 string | number,想直接使用 length 属性,则需要通过类型断言指定 x 的属性为 string
}
-
特殊
当我们声明可选参数时,我们需要先判断参数存在才能使用
function myFun(x: number, y?: number): number {
if (y) {
const result = x + y; // 不进行判断将会报错
return result;
}
}
// 也可通过断言
function myFun(x: number, y?: number): number {
const result = x + !y; // !表示改变量一定存在
return result;
}
注意:类型断言不是类型转换,断言一个联合类型中不存在的类型将会报错。
声明文件
当我们直接在项目中引入第三方的模块,并且使用其方法或者是属性,ts 是不会报错的,因为这些类型和方法都是没有进行声明的。因为我们需要使用声明文件来定义这些属性和方法的类型。对于一些常用的第三方模块, typescript 社区已经帮我们定义好了,只要我们在使用 npm 安装模块的时候,在模块名前带上 @type/
npm install express --save// 安装普通的 express 模块
npm install @/types/express --save-dev// 安装带有声明文件的 express 模块,只有本地开发环境才进行安装
对于一些不常用的第三方模块,在 typescript 社区中无法安装带有声明文件的模块,我们可以在项目的根目录下创建一个 index.d.ts 文件,在其中对其进行声明,防止 ts 报错。
declare module "so-utils"; // 声明 so-utils 为一个模块,防止 import * from 'so-utils' 报错
以上可防止模块引入时报错,但对于模块定义的属性和方法依旧没有提示,想要完整的代码提示功能则要定义完整的声明文件,关于声明文件的书写名,参见TypeScript 入门教程 - 声明文件
内置对象
JavaScript 中有很多定义好的对象,我们可以当作定义好的类型来使用。
let bodyDoc: HTMLDocument = document.body; // html文档流
类型别名
我们使用 type 关键字来声明类型的别名
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === "string") {
return n;
} else {
return n();
}
}
字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串取值中一个
type eventName = "click" | "scroll" | "mousemove";
// 第二个参数 event 只能是'click' | 'scroll' | 'mousemove'三个中的某一个
function handleEvent(ele: Element, event: EventNames) {
// do something
}
handleEvent(doument.getELementById("hello"), "scroll"); // true
handleEvent(doument.getELementById("hello"), "dbclick"); // 报错