本篇主要是整理一下 typescript 相关的知识点,实际的运用会在下篇文章仔细讲解。html
TypeScript 是 JavaScript 的一个超级,主要提供了类型系统和对 ES6 的支持。es6
npm -g install typescrip // 全局安装 typescript
复制代码
全局安装 typescript 后便可在终端使用 tsc 命令了,编译 ts 文件命令以下:typescript
// hello.ts
function foo(name: string) {
console.log(`Hello ${name}`);
}
foo('Cooper') // Hello Cooper
tsc hello.ts // 编译 ts 文件后生成对应的 hello.js 文件
复制代码
Ts 只会进行静态类型检查,若是发现错误,编译的时候就会报错。平常通常搭配 Eslint 或 Tslint 使用,在编码过程当中即会报出对应错误。express
经过在变量后加 :类型 声明变量的类型。npm
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 对象。其余基本数据类型亦如此数组
let num: number = 3; // 正确
num = '3'; // 报错,申明了变量为 number 类型,怎么能赋 string 类型的值呀!
复制代码
let name: string = 'Cooper';
let templetStr: string = `Hello, ${name}`; // es6 模版字符串
复制代码
JavaScript 中没有空值(Void)的概念,在 TypeScript 中空值通常用来表示一个函数没有返回值bash
// 定义一个没有返回值的返回的函数
function foo(name: string): void {
console.log(name)
}
复制代码
定义为 null 类型的变量只能被赋值为 null, 定义为 undefined 的变量只能被赋值为 undefined函数
let u: undefined = undefined;
let m: null = null;
复制代码
定义为任意值的变量能够被赋值为任意类型。在任意类型的变量上访问任意属性和方法都是能够的。声明一个变量为 any 类型后,对其进行任意操做返回的都是 any 类型。未声明类型的变量默认为 any 类型。oop
let anyValue: any = '123';
anyValue = 1; // 不会报错,由于 anyValue 的类型为任意值
复制代码
注意:any 用起来虽然特别方便,可是建议平常开发能不用就不用,毕竟 TypeScript 是为了更规范的书写 Js 代码,若是所有都定义成 any 类型,那就失去了 TypeScript 的意义。ui
若是没有明确的指明某个变量的类型, 那么 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; // 上面定义的具体类型也应包含在任意类型
}
复制代码
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 类型
复制代码
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'); // 报错
复制代码