安装Typescript 1.安装 //安装 npm install -g typescript //编译 tsc hello.ts //初始化 tsc –init 基础入门 Typescript可以理解为带静态类型的Javascript;

1.原始数据类型

布尔值,boolean 数值,number 字符串,string 空值,void 表示没有任何返回值的函数 Null 和 Undefined

/* 先声明后使用 */ let a: string; a = “aaa”; /声明的同时赋值/ let b: string = “aaa”; /类型推论/ let c = false; c = 1; //报错,类型推论得出c为布尔值

2.任意值(any) 如果是一个普通类型,在赋值过程中改变类型是不被允许的:

let myFavoriteNumber: string = ‘seven’; myFavoriteNumber = 7; // index.ts(2,1): error TS2322: Type ‘number’ is not assignable to type ‘string’.

但如果是 any 类型,则允许被赋值为任意类型。

let myFavoriteNumber: any = ‘seven’; myFavoriteNumber = 7; 

3.联合类型 联合类型(Union Types)表示取值可以为多种类型中的一种,联合类型使用 | 分隔每个类型。

let myFavoriteNumber: string | number; myFavoriteNumber = ‘seven’; myFavoriteNumber = 7; let myFavoriteNumber: string | number; myFavoriteNumber = true; // index.ts(2,1): error TS2322: Type ‘boolean’ is not assignable to type ‘string | number’. // Type ‘boolean’ is not assignable to type ‘number’. 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法

function getLength(something: string | number): number {

return something.length;//访问length报错,以为number没有length属性
return something.toString; //不报错,toString是共有属性

}

4.对象的类型—接口 在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

interface Person {

name: string;
age: number;

} let tom: Person = {

name: 'Tom',
age: 25

};

定义的变量比接口少、多一些属性是不允许的,赋值的时候,变量的形状必须和接口的形状保持一致。

4.1 可选属性 可选属性的含义是该属性可以不存在,但是仍然不允许添加未定义的属性。

interface Person {

name: string;
age?: number;

} let tom: Person = {

name: 'Tom'

};

4.2 任意属性 有时候我们希望一个接口允许有任意的属性,可以使用如下方式:

interface Person {

name: string;
age?: number;
[propName: string]: any;

} let tom: Person = {

name: 'Tom',
gender: 'male'

};

[propName: string] string 4.3 只读属性 有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性

interface Person {

readonly id: number;
name: string;
age?: number;
[propName: string]: any;

} let tom: Person = {

id: 89757,
name: 'Tom',
gender: 'male'

}; tom.id = 9527; // index.ts(14,5): error TS2540: Cannot assign to ‘id’ because it is a constant or a read-only property.

只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

5.数组的类型 //最简单的方法是使用「类型 + 方括号」来表示数组 let fibonacci: number[] = [1, 1, 2, 3, 5]; //数组泛型(Array Generic) Array<elemType> let fibonacci: Array<number> = [1, 1, 2, 3, 5]; //接口也可以用来描述数组 interface NumberArray {

[index: number]: number;

} let fibonacci: NumberArray = [1, 1, 2, 3, 5]; //任意类型的数组 ley arr:any=[1,“2”,false];

6.函数的类型 在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression):

// 函数声明(Function Declaration) function sum(x, y) {

return x + y;

} // 函数表达式(Function Expression) let mySum = function (x, y) {

return x + y;

};

一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单:

function sum(x: number, y: number): number {

return x + y;

}

函数表达式定义如下:

let mySum: (x: number, y: number) => number = function (x: number, y: number): number {

return x + y;

};

我们也可以使用接口的方式来定义一个函数需要符合的形状:

interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc;

mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;

6.1 可选参数  与接口中的可选属性类似,我们用 ? 表示可选的参数:

function buildName(firstName: string, lastName?: string) {

if (lastName) {
    return firstName + ' ' + lastName;
} else {
    return firstName;
}

} let tomcat = buildName(‘Tom’, ‘Cat’); let tom = buildName(‘Tom’);

6.2 参数默认值 在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数,此时就不受「可选参数必须接在必需参数后面」的限制了:

function buildName(firstName: string, lastName: string = ‘Cat’) {

return firstName + ' ' + lastName;

} let tomcat = buildName(‘Tom’, ‘Cat’); let tom = buildName(‘Tom’);

6.3 剩余参数 ES6 中,可以使用 …rest 的方式获取函数中的剩余参数(rest 参数):

function push(array, …items) { items.forEach(function(item) {

  array.push(item);

}); } let a: any[] = []; push(a, 1, 2, 3);

事实上,items 是一个数组。所以我们可以用数组的类型来定义它:

function push(array: any[], …items: any[]) { items.forEach(function(item) {

    array.push(item);

}); } let a = []; push(a, 1, 2, 3);

注意,rest 参数只能是最后一个参数,关于 rest 参数,可以参考 ES6 中的 rest 参数。

6.4 重载 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string | void {

if (typeof x === 'number') {
    return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
    return x.split('').reverse().join('');
}

}

7.类型断言 类型断言(Type Assertion)可以用来手动指定一个值的类型。

值 as 类型 / <类型>值

需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:

interface Cat {

name: string;
run(): void;

} interface Fish {

name: string;
swim(): void;

} function swim(animal: Cat | Fish) {

(animal as Fish).swim();

} const tom: Cat = {

name: 'Tom',
run() { console.log('run') }

}; swim(tom); // Uncaught TypeError: animal.swim is not a function`

8.声明文件 //定义了全局变量 jQuery 的类型 declare var jQuery: (selector: string) => any; jQuery(‘#foo’);

进阶 1.类型别名 type Name = string; type NameResolver = () => string; type NameOrResolver = Name | NameResolver;

2.字符串字面量类型 type EventNames = ‘click’ | ‘scroll’ | ‘mousemove’; function handleEvent(ele: Element, event: EventNames) {

// do something

} handleEvent(document.getElementById(‘hello’), ‘scroll’); // 没问题 handleEvent(document.getElementById(‘world’), ‘dblclick’); // 报错,event 不能为 ‘dblclick’

3.元组 数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。

//定义一对值分别为 string 和 number 的元组 let tom: [string, number] = [‘Tom’, 25];

当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:

let tom: [string, number]; tom = [‘Tom’, 25]; tom.push(‘male’); tom.push(true); // Argument of type ‘true’ is not assignable to parameter of type ‘string | number’.

4.枚举 枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。

枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; console.log(Days[“Sun”] === 0); // true console.log(Days[“Mon”] === 1); // true console.log(Days[“Tue”] === 2); // true console.log(Days[“Sat”] === 6); // true console.log(Days[0] === “Sun”); // true console.log(Days[1] === “Mon”); // true console.log(Days[2] === “Tue”); // true console.log(Days[6] === “Sat”); // true

编译后:

var Days; (function (Days) {

Days[Days["Sun"] = 0] = "Sun";
Days[Days["Mon"] = 1] = "Mon";
Days[Days["Tue"] = 2] = "Tue";
Days[Days["Wed"] = 3] = "Wed";
Days[Days["Thu"] = 4] = "Thu";
Days[Days["Fri"] = 5] = "Fri";
Days[Days["Sat"] = 6] = "Sat";

})(Days || (Days = {})); 5.类与接口 实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。

6.泛型 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function createArray<T>(length: number, value: T): Array<T> {

let result: T[] = [];
for (let i = 0; i < length; i++) {
    result[i] = value;
}
return result;

} createArray<string>(3, ‘x’); // [‘x’, ‘x’, ‘x’]

定义泛型的时候,可以一次定义多个类型参数:

function swap<T, U>(tuple: [T, U]): [U, T] {

return [tuple[1], tuple[0]];

} swap([7, ‘seven’]); // [‘seven’, 7]

7.声明合并 如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型:

function reverse(x: number): number; function reverse(x: string): string; function reverse(x: number | string): number | string {

if (typeof x === 'number') {
    return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
    return x.split('').reverse().join('');
}

}

内置对象 Typescript内置了所有js、dom对象,核心库类型定义文件:https://github.com/Microsoft/TypeScript/tree/main/src/lib

命名空间 使用 namespace 关键字定义命名空间,可以在命名空间内部定义变量、函数表达式、函数声明、接口和 类等值。

为了让命名空间外部可以访问命名空间内部声明的值和类型,使用 export 关键字导出指定的值和类型;

namespace Tools { var count = 0 //导出 add export var add = function (x: number, y: number) {

return x + y

} }

引用外部文件的命名空间内的成员时,需要export指定命名空间

exprot namespace {

let a:any=1;
export {a}

}

相关总结 enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; console.log(Days[“Sun”] === 0); // true console.log(Days[“Mon”] === 1); // true console.log(Days[“Tue”] === 2); // true console.log(Days[“Sat”] === 6); // true console.log(Days[0] === “Sun”); // true console.log(Days[1] === “Mon”); // true console.log(Days[2] === “Tue”); // true console.log(Days[6] === “Sat”); // truefunction createArray(length: number, value: any): Array<any> {

let result = [];
for (let i = 0; i < length; i++) {
    result[i] = value;
}
return result;

} createArray(3, ‘x’); // [‘x’, ‘x’, ‘x’]

Es6 类 1.属性和方法 class Animal {

public name;
constructor(name) {
    this.name = name;
}
sayHi() {
    return `My name is ${this.name}`;
}

} let a = new Animal(‘Jack’); console.log(a.sayHi()); // My name is Jack

2.类的继承 使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法

class Cat extends Animal { constructor(name) {

super(name); // 调用父类的 constructor(name)
console.log(this.name);

} sayHi() {

return 'Meow, ' + super.sayHi(); // 调用父类的 sayHi()

} } let c = new Cat(‘Tom’); // Tom console.log(c.sayHi()); // Meow, My name is Tom

3.存取器 使用 getter 和 setter 可以改变属性的赋值和读取行为:

class Animal { constructor(name) {

this.name = name;

} get name() {

return 'Jack';

} set name(value) {

console.log('setter: ' + value);

} } let a = new Animal(‘Kitty’); // setter: Kitty a.name = ‘Tom’; // setter: Tom console.log(a.name); // Jack

4.静态方法 使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:

class Animal { static isAnimal(a) {

return a instanceof Animal;

} } let a = new Animal(‘Jack’); Animal.isAnimal(a); // true a.isAnimal(a); // TypeError: a.isAnimal is not a function

Es7 类 Es7相关提案在Typescript中已实现。

1.实例属性 ES6 中实例的属性只能通过构造函数中的 this.xxx 来定义,ES7 提案中可以直接在类里面定义:

class Animal { name = ‘Jack’; constructor() {

// ...

} } let a = new Animal(); console.log(a.name); // Jack

2.静态属性 ES7 提案中,可以使用 static 定义一个静态属性:

class Animal { static num = 42; constructor() {

// ...

} } console.log(Animal.num); // 42

TypeScript 中类的用法  TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。

public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的 private 修饰的属性或方法是私有的,不能在声明它的类的外部访问 protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的

1.抽象类 abstract 用于定义抽象类和其中的抽象方法

abstract class Animal { public name; public constructor(name) {

this.name = name;

} public abstract sayHi(); } let a = new Animal(‘Jack’); // index.ts(9,11): error TS2511: Cannot create an instance of the abstract class ‘Animal’.

tsconfig.json 如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。

{ // … “compilerOptions”: {

"incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印诊断信息 
"target": "ES5", // 目标语言的版本
"module": "CommonJS", // 生成代码的模板标准
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
"allowJS": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"declarationDir": "./file", // 指定生成声明文件存放目录
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"sourceMap": true, // 生成目标文件的sourceMap文件
"inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
"declarationMap": true, // 为声明文件生成sourceMap
"typeRoots": [], // 声明文件目录,默认时node_modules/@types
"types": [], // 加载的声明文件包
"removeComments":true, // 删除注释 
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
"noEmitOnError": true, // 发送错误时不输出任何文件
"noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
"importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
"strictBindCallApply": true, // 严格的bind/call/apply检查
"noImplicitThis": true, // 不允许this有隐式的any类型
"noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
"noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"noImplicitReturns": true, //每个分支都会有返回值
"esModuleInterop": true, // 允许export=导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
"moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": { // 路径映射,相对于baseUrl
  // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
  "jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
"listEmittedFiles": true, // 打印输出文件
"listFiles": true// 打印编译的文件(包括引用的声明文件)

}, “exclude”: [

"src/lib" // 排除src目录下的lib文件夹下的文件不会编译

], “files”: [

// 指定编译文件是src目录下的leo.ts文件
"scr/leo.ts"

], “include”: [

// "scr" // 会编译src目录下的所有文件,包括子目录
// "scr/*" // 只会编译scr一级目录下的文件
"scr/*/*" // 只会编译scr二级目录下的文件

] }

声明文件 1.相关语法 ts中的相关语法:

declare var 声明全局变量 declare function 声明全局方法 declare class 声明全局类 declare enum 声明全局枚举类型 declare namespace 声明(含有子属性的)全局对象 interface 和 type 声明全局类型 export 导出变量 export namespace 导出(含有子属性的)对象 export default ES6 默认导出 export = commonjs 导出模块 export as namespace UMD 库声明全局变量 declare global 扩展全局变量 declare module 扩展模块 /// 三斜线指令

declare module ‘cos’:

如果你使用了一个 JavaScript 库(如 cos),但该库没有提供 .d.ts 类型定义文件,你可以通过 declare module 手动声明该模块的类型。这可以让 TypeScript 编译器理解模块的结构,从而提供类型检查和智能提示。

如果 cos 已经有类型定义,但你希望为其添加新的类型扩展,也可以使用 declare module。

declare module ‘cos’ {

export interface Config {
    timeout?: number;
}

} 2.三斜线指令 三斜线指令也是 ts 在早期版本中为了描述模块之间的依赖关系而创造的语法。随着 ES6 的广泛应用,现在已经不建议再使用 ts 中的三斜线指令来声明模块之间的依赖关系了。

/// <reference path=“…” /> #按路径引入 /// <reference types=“…” /> #按包名引入

类似于声明文件中的 import,它可以用来导入另一个声明文件。与 import 的区别是,当且仅当在以下几个场景下,我们才需要使用三斜线指令替代 import:

当我们在书写一个全局变量的声明文件时,在全局变量的声明文件中,是不允许出现 import, export 关键字的。一旦出现了,那么他就会被视为一个 npm 包或 UMD 库,就不再是全局变量的声明文件了。故当我们在书写一个全局变量的声明文件时,如果需要引用另一个库的类型,那么就必须用三斜线指令 当我们需要依赖一个全局变量的声明文件时,当我们需要依赖一个全局变量的声明文件时,由于全局变量不支持通过 import 导入,当也就必须使用三斜线指令来引入 拆分声明文件,当我们的全局变量的声明文件太大时,可以通过拆分为多个文件,然后在一个入口文件中将它们一一引入,来提高代码的可维护性。

3.d.ts文件 ts 会解析项目中所有的 *.ts 文件、 .d.ts 结尾的文件。所以全局类型声明放在.d.ts中,可直接使用,不需要手动去引入。非全局则需要引入

问题总结 1.通过下标获取对象属性 ts直接通过属性名下标访问对象属性会报错,需要通过keyof处理。

阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。