对于为第三方模块/库写声明文件以前,咱们须要知道第三方模块/库,是否须要声明文件,或者是否已有声明文件。html
--declaration
配置选项来生成; 能够在命令行中添加 --declaration(简写 -d),或者在 tsconfig.json 中添加 declaration:true 选项1. 与该 npm 包绑定在一块儿,能够经过查找该库的`package.json`中的`types`属性
2. 发布到 @types 里,能够在官方提供的第三方声明文件库(http://microsoft.github.io/TypeSearch/)中查找
复制代码
如若上面的状况都不符合, 则须要咱们本身手写声明文件vue
在书写声明文件以前,咱们须要了解Typescript 相关知识, 能够自行查阅官方文档,或阅读我前一篇TypeScript 总结篇, 固然有须要写声明文件的须要,确定是对Typescript有了解,可能已有相关实践,在此只是友情提示。 除此以外还须要对TS中的模块化有所了解,以下git
主要是解决加载依赖关系的,侧重代码的复用。跟文件绑定在一块儿,一个文件就是一个module,模块写法和ES6同样。github
同Java的包、.Net的命名空间同样,TypeScript的命名空间将代码包裹起来,经过export关键字对外暴露须要在外部访问的对象。 主要用于组织代码,解决命名冲突,会在全局生成一个对象,定义在namespace内部的都要经过这个对象的属性访问。ajax
随着 ES6 的普遍应用,现已经不建议使用 ts 中的 namespace,而推荐使用 ES6 模块化方案,但在声明文件中,declare namespace 仍是比较经常使用的。typescript
namespace声明能够用来添加新类型,值和命名空间,只要不出现冲突。
与class/namespace等类型合并npm
///<reference types=“UMDModuleName/globalName” />
ts 早期模块化的标签, 用来导入依赖, ES6普遍使用后, 在编写TS文件中不推荐使用, 除了如下的场景使用///
, 其余场景使用 import
代替
在声明文件中, 依赖全局库或被全局库依赖, 具体:json
注意
: 三斜线指令必须放在文件的最顶端,三斜线指令的前面只容许出现单行或多行注释。数组
模块或一个 UMD 库依赖于一个 UMD 库,使用 import * as 语句引入模块bash
第三方库使用场景:
<script>
标签引入第三方库,注入全局变量import foo from 'foo'
导入,符合ES6
模块规范<script>
标签引入,又能够经过 import
导入import
导入后,能够改变另外一个模块的结构<script>
标签引入后,改变一个全局变量的结构。好比为String.prototype
新增了一个方法import
导入后,能够改变一个全局变量的结构类库分为三类:全局类库、模块类库、UMD类库
经过<script>
标签引入第三方库, 注入全局变量 全局变量的声明文件主要有如下几种语法:
主要看下 declare namespace
// src/jQuery.d.ts
declare namespace jQuery {
const version: number;
class Event {
blur(eventType: EventType): void
}
enum EventType {
CustomClick
}
interface AjaxSettings {
method?: 'GET' | 'POST'
data?: any;
}
function ajax(url: string, settings?: AjaxSettings): void;
}
复制代码
declare namespace
声明全局命名空间,去掉declare namespace
, 即从中提出代码,再在前面加上declare
便是声明各全局变量
// 声明全局函数,其余同理
declare function ajax(url: string, settings?: any): void;
复制代码
在npm包中, 经过import foo from 'foo'
导入npm包。npm 包的声明文件主要有如下几种语法:
export // 导出变量
export namespace // 导出(含有子属性的)对象
export default // ES6 默认导出
export = // commonjs 导出模块
复制代码
在 npm 包的声明文件中,使用 declare 再也不会声明一个全局变量,而只会在当前文件中声明一个局部变量。只有在声明文件中使用 export 导出,而后在使用方 import 导入后,才会应用到这些类型声明。
与非声明文件写法相似, 使用import导入, ES6模块语法
使用 declare 先声明多个变量,最后再用 export 一次性导出
注: interface 前是不须要 declare 的
注意,只有 function、class 和 interface 能够直接默认导出,其余的变量须要先定义出来,再默认导出
用来导出一个拥有子属性的对象
在 commonjs 规范中, 使用exports/module.exports
导出模块, 针对这类模块的声明文件,须要使用export =
导出
declare module "a" {
export let a: number
export function b(): number
export namespace c{
let cd: string
}
}
import * as A from 'a'
A.a //
A.b()
A.c.cd //
复制代码
// 函数
declare module 'app' {
function fn(some:number):number
export = fn
}
const app = reqiure('app')
app()// 调用fn
复制代码
// 变量/常量
declare module 'let' {
let oo:number = 2
export = oo
}
const o = reqiure('let')
o // 使用
复制代码
既能够经过 <script>
标签引入,又能够经过 import 导入的库,称为 UMD 库。相比于 npm 包的类型声明文件,须要额外声明一个全局变量,为了实现这种方式,ts 提供了一个新语法 export as namespace
export as namespace
做用: 局部变量生命为全局变量
通常使用 export as namespace 时,都是已有 npm 包的声明文件,再基于它添加一条 export as namespace 语句,便可将声明好的一个变量声明为全局变量
// types/foo/index.d.ts
export as namespace foo; // 全局导出
export = foo; // or export default foo; 导出npm模块
declare function foo(): string;
declare namespace foo {
const bar: number;
}
复制代码
// global.extend.d.ts
interface String {
prependHello(): string;
}
复制代码
// src/index.ts
'xx'.prependHello()
复制代码
对于一个 npm 包或者 UMD 库的声明文件,只有 export 导出的类型声明才能被导入 导入此库以后能够扩展全局变量, 须要使用 declare global
// types/foo/index.d.ts
declare global {
interface String {
prependHello(): string;
}
}
export default function foo(): string;
复制代码
// src/index.ts
import foo from './foo'
'bar'.prependHello()
复制代码
导入一个模块插件, 改变原有模块结构, 原有模块已有声明文件, 导入的模块插件没有声明文件
// types/moment-plugin/index.d.ts
import * as moment from 'moment'; // 原有模块
declare module 'moment' {
export function foo(): moment.CalendarKey;
}
复制代码
// src/index.ts
import * as moment from 'moment';
import 'moment-plugin';
moment.foo();
复制代码
declare module 也可用于在一个文件中一次性声明多个模块的类型
// types/foo-bar.d.ts
declare module 'foo' {
export interface Foo {
foo: string;
}
}
declare module 'bar' {
export function bar(): string;
}
复制代码
// src/index.ts
import { Foo } from 'foo';
import * as bar from 'bar';
let f: Foo;
bar.bar();
复制代码
Ambient Declarations(通称:外部模块定义) ,主要为项目内全部的 vue 文件作模块声明,毕竟 ts 默认只识别 .d.ts、.ts、.tsx 后缀的文件;(即便补充了 Vue 得模块声明,IDE 仍是无法识别 .vue 结尾的文件,这就是为何引入 vue 文件时必须添加后缀的缘由,不添加编译也不会报错)
JSX 语法的全局命名空间,这是由于基于值的元素会简单的在它所在的做用域里按标识符查找(此处使用的是**无状态函数组件 (SFC)**的方法来定义),当在 tsconfig 内开启了 jsx 语法支持后,其会自动识别对应的 .tsx 结尾的文件,可参考官网 jsx
静态类型、动态类型和弱类型、强类型
静态类型:编译期就知道每个变量的类型。类型错误编译失败是语法问题。如Java、C++
动态类型:编译期不知道类型,运行时才知道。类型错误抛出异常发生在运行时。如JS、Python
弱类型:容忍隐式类型转换。如JS,1+'1'='11',数字型转成了字符型
强类型:不容忍隐式类型转换。如Python,1+'1'会抛出TypeError
关于我对声明文件的实践,详见ts-declare, 另外,关于文章中,不对/不妥之处,欢迎指出,感谢~
www.tslang.cn/docs/handbo… ts.xcatliu.com/basics/decl…
zhuanlan.zhihu.com/p/58123993
blog.poetries.top/2019/09/03/…
juejin.im/post/5d22b1…