12.类型声明

460 阅读3分钟

12.类型声明

  • 声明文件可以让我们不需要将JS重构为TS,只需要加上声明文件就可以使用系统

  • 类型声明在编译的时候都会被删除,不会影响真正的代码

  • 关键字 declare 表示声明的意思,我们可以用它来做出各种声明:


declare var 声明全局变量

declare function 声明全局方法

declare class 声明全局类

declare enum 声明全局枚举类型

declare namespace 声明(含有子属性的)全局对象

interface 和 type 声明全局类型

12.1 普通类型声明


declare let name: string; //变量

declare let age: number; //变量

declare function getName(): string; //方法

declare class Animal { name: string } //类

console.log(name, age);

getName();

new Animal();

export default {};

声明jQuery对象


declare const $: (selector: string) => { //变量

click(): void;

width(length: number): void;

};

$('#root').click();

console.log($('#root').width);

12.2 外部枚举

  • 外部枚举是使用declare enum定义的枚举类型

  • 外部枚举用来描述已经存在的枚举类型的形状


declare enum Seasons {

Spring,

Summer,

Autumn,

Winter

}

let seasons = [

Seasons.Spring,

Seasons.Summer,

Seasons.Autumn,

Seasons.Winter

];

declare 定义的类型只会用于编译时的检查,编译结果中会被删除。上例的编译结果如下


var seasons = [

Seasons.Spring,

Seasons.Summer,

Seasons.Autumn,

Seasons.Winter

];

也可以同时使用declare 和 const


declare const enum Seasons {

Spring,

Summer,

Autumn,

Winter

}

let seasons = [

Seasons.Spring,

Seasons.Summer,

Seasons.Autumn,

Seasons.Winter

];

编译结果


var seasons = [

0 /* Spring */,

1 /* Summer */,

2 /* Autumn */,

3 /* Winter */

];

12.3 namespace

  • 如果一个全局变量包括了很多子属性,可能使用namespace

  • 在声明文件中的namespace表示一个全局变量包含很多子属性

  • 在命名空间内部不需要使用 declare 声明属性或方法


declare namespace ${

function ajax(url:string,settings:any):void;

let name:string;

namespace fn {

function extend(object:any):void;

}

}

$.ajax('/api/users',{});

$.fn.extend({

log:function(message:any){

console.log(message);

}

});

export {};

12.4 类型声明文件

  • 我们可以把类型声明放在一个单独的类型声明文件中

  • 可以在类型声明文件中使用类型声明

  • 文件命名规范为*.d.ts

  • 观看类型声明文件有助于了解库的使用方式

12.4.1 jquery.d.ts

typings\jquery.d.ts


declare const $:(selector:string)=>{

click():void;

width(length:number):void;

}

12.4.2 tsconfig.json

tsconfig.json


{

"compilerOptions": {

"module": "commonjs",

"target": "ES2015",

"outDir":"lib"

},

"include": [

"src/**/*",

"typings/**/*"

]

}

12.4.3 test.js

src\test.ts


$('#button').click();

$('#button').width(100);

export {};

第三方声明文件

  • 可以安装使用第三方的声明文件

  • @types是一个约定的前缀,所有的第三方声明的类型库都会带有这样的前缀

  • JavaScript 中有很多内置对象,它们可以在 TypeScript 中被当做声明好了的类型

  • 内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准

  • 这些内置对象的类型声明文件,就包含在TypeScript 核心库的类型声明文件中

12.5.1 使用jquery


cnpm i jquery -S


//对于common.js风格的模块必须使用 import * as

import * as jQuery from 'jquery';

jQuery.ajax('/user/1');

12.5.2 安装声明文件


cnpm i @types/jquery -S

12.5.3 自己编写声明文件

  • 模块查找规则

  • node_modules@types\jquery/index.d.ts

  • 我们可以自己编写声明文件并配置tsconfig.json

12.5.3.1 index.d.ts

types\jquery\index.d.ts


declare function jQuery(selector:string):HTMLElement;

declare namespace jQuery{

function ajax(url:string):void

}

export default jQuery;

12.5.3.2 tsconfig.json

  • 如果配置了paths,那么在引入包的的时候会自动去paths目录里找类型声明文件

  • 在 tsconfig.json 中,我们通过 compilerOptions 里的 paths 属性来配置路径映射

  • paths是模块名到基于baseUrl的路径映射的列表


{

"compilerOptions": {

"baseUrl": "./",// 使用 paths 属性的话必须要指定 baseUrl 的值

"paths": {

"*":["types/*"]

}

}


import $ from "jquery";

$.ajax('get');

12.5.4 npm声明文件可能的位置

  • node_modules/jquery/package.json

  • "types":"types/xxx.d.ts"

  • node_modules/jquery/index.d.ts

  • node_modules/@types/jquery/index.d.ts

  • typings\jquery\index.d.ts

12.5.5 查找声明文件

  • 如果是手动写的声明文件,那么需要满足以下条件之一,才能被正确的识别

  • 给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址

  • 在项目根目录下,编写一个 index.d.ts 文件

  • 针对入口文件(package.json 中的 main 字段指定的入口文件),编写一个同名不同后缀的 .d.ts 文件


{

"name": "myLib",

"version": "1.0.0",

"main": "lib/index.js",

"types": "myLib.d.ts",

}

`

  • 先找myLib.d.ts

  • 没有就再找index.d.ts

  • 还没有再找lib/index.d.js

  • 还找不到就认为没有类型声明了

12.6 扩展全局变量的类型

12.6.1 扩展局部变量类型


declare var String: StringConstructor;

interface StringConstructor {

new(value?: any): String;

(value?: any): string;

readonly prototype: String;

}

interface String {

toString(): string;

}


interface String {

double():string;

}

String.prototype.double = function(){

return this+'+'+this;

}

console.log('hello'.double());

//扩展类的实例

interface Window{

myname:string

}

console.log(window.myname);

//export {} 没有导出就是全局扩展

12.6.2 模块内全局扩展

types\global\index.d.ts


interface String {

double():string;

}

interface Window{

myname:string

}

}

export {}

12.7 合并声明

  • 同一名称的两个独立声明会被合并成一个单一声明

  • 合并后的声明拥有原先两个声明的特性

| 关键字 |作为类型使用 | 作为值使用 |

| --- | --- | --- |

| class | yes | yes |

| enum | yes |yes |

| interface |yes | no |

|type |yes | no |

| function | no | yes |

| var,let,const |no | yes|

  • 类既可以作为类型使用,也可以作为值使用,接口只能作为类型使用

class Person{

name:string=''

}

let p1:Person;//作为类型使用

let p2 = new Person();//作为值使用

interface Animal{

name:string

}

let a1:Animal;

let a2 = Animal;//接口类型不能用作值

12.7.1 合并类型声明

  • 可以通过接口合并的特性给一个第三方为扩展类型声明

use.js


interface Animal{

name:string

}

let a1:Animal={name:'zhufeng',age:10};

console.log(a1.name);

console.log(a1.age);

//注意不要加export {} ,这是全局的

types\animal\index.d.ts


interface Animal{

age:number

}

12.7.2 使用命名空间扩展类

  • 我们可以使用 namespace 来扩展类,用于表示内部类

class Form {

username: Form.Item='';

password: Form.Item='';

}

//Item为Form的内部类

namespace Form {

export class Item {}

}

let item:Form.Item = new Form.Item();

console.log(item);

12.7.3 使用命名空间扩展函数

  • 我们也可以使用 namespace 来扩展函数

function greeting(name: string): string {

return greeting.words+name;

}

namespace greeting {

export let words = "Hello,";

}

console.log(greeting('zhufeng'))

12.7.4 使用命名空间扩展枚举类型


enum Color {

red = 1,

yellow = 2,

blue = 3

}

namespace Color {

export const green=4;

export const purple=5;

}

console.log(Color.green)

12.7.5 扩展Store


import { createStore, Store } from 'redux';

type StoreExt = Store & {

ext: string

}

let store: StoreExt = createStore(state => state);

store.ext = 'hello';

12.8 生成声明文件

  • 把TS编译成JS后丢失类型声明,我们可以在编译的时候自动生成一份JS文件

{

"compilerOptions": {

"declaration": true, /* Generates corresponding '.d.ts' file.*/

}

}