TypeScript初识

JavaScript没有类型检测,这会让我们的代码不安全,TS可以很好的解决这个问题

TS简介

Typescript是拥有类型的JavaScript超集

JavaScript所拥有的特性,TS全部都支持,并且在语言层面上添加了类型约束,还加上一些语法的扩展

TS的编译环境

TS最终还是会被编译成JS代码运行,所以我们需要搭建对应的环境

在电脑上安装Typescript,这样就可以通过TypeScript的Compiler将其编译成JavaScript

全局安装:npm install typescript -g

查看版本:tsc --version

TS的运行环境

运行的两个步骤:

  1. tsc xxx.ts 把ts文件编译成JS代码
  2. 在浏览器或Node环境下运行JS代码

如果每次都要做这两个步骤,那就太麻烦了

有什么简化的方式呢?

第一种:通过webpack,配置本地的TS编译环境和开启一个本地服务,可以直接运行在浏览器上

image.png image.png

第二种:通过ts-node库,为TS的运行提供执行环境

  • 安装 ts-node:npm install ts-node -g

  • 另外 ts-node需要安装依赖 tslib 和 @types/node 两个包

    npm install tslib @types/node -g

  • 然后可以直接通过 ts-node 来运行 TS 的代码:

    ts-node xxx.ts

变量的声明

  • 定义的时候给标识符加类型: var/let/const 标识符: 数据类型 = 赋值

    但是 var 不推荐使用

    另外注意 string 和 String 的区别

    string是TypeScript中定义的字符串类型,String是ECMAScript中定义的一个包装类

    let message: string = "abc"
    console.log(message);

    const name: string = 'xxx'
  • 类型推断(推导),就是说我们第一次给变量赋值的时候,会根据这个赋值的内容,自动推断变量的类型

    let num = 2 // 自动类型推断为number类型
    num = "123" // 报错

推荐:如果可以自动推导出变量的类型的时候,不加类型

不确定类型的时候,要自己加上类型

数据类型

我们常说TS是JS的一个超集

image.png

JS类型

TS和JS都有的数据类型

  1. number类型

TS 和 JS一样

let num: number = 123
num = 222

// num = "123" // 报错

// TS 也支持进制
let num1: number = 100
let num2: number = 0b100
let num3: number = 0o100
let num4: number = 0x100

console.log(num1, num2, num3, num4); // 100 4 64 256
  1. boolean类型

true、false

let flag: boolean = truelet flag: boolean = true
flag = false
flag = 20 > 30
  1. string类型
let message: string = "hello"
message = 'hello ts'

// 同样也支持ES6的模板字符串
const info = `hi ${message}`
console.log(info); // hi hello ts
  1. Array类型

固定数组里面存放的数据类型

const name1: string[] = [] // 推荐
// name1.push(1) // 报错

const name2: Array<string> = [] // 不推荐(react jsx中是有冲突)
  1. Object类型
const info:object = {  // 在这里设置了object类型
name: "xxx",
age: 18
}

info["name"] = "kkk"
console.log(info["age"]);

设置了object类型不能获取数据也不能设置数据
image.png

如果去掉了:object就可以获取,并且里面的属性类型也有推断

const info = {
name: "xxx",
age: 18
}

info["name"] = 123 // 报错
console.log(info["age"]) // 18
  1. Symbol类型

跟 JS 一样,主要用于设置唯一属性名

let title1: symbol = Symbol("title")
// title1 = 2 // number赋值给symbol类型,报错

let title2 = Symbol("title") // 推断
const info = {
[title1]: "xxx",
[title2]: "kkk"
}
  1. Null 和 Undefined类型

null:

let n1: null = null
n1 = 123 // number -> null 报错

let n2 = null // 推断是 any类型
n2 = 123 // 不报错

同理:undefined:

let n3: undefined = undefined
n3 = 123 // 报错

let n4 = undefined
n4 = 123

TypeScript类型

any类型

any表示任意类型

在不确定变量类型的时候,可以使用any类型,但是一旦使用了,意味着我们可以对any类型的变量进行任何的操作,包括赋值任何类型的值;获取不存在的属性、方法

非常不安全,不推荐使用

let message: any = "hello"

message = 123
message = true
message = {}

message.split(" ")

unknown类型

用于描述类型不确定的变量

unknown类型只能赋值给any和unknown类型

function foo() {
return "abc"
}

function bar() {
return 123
}

let flag = true
let result: unknown // 如果使用any就不会报错了

if (flag) {
result = foo()
} else {
result = bar()
}

// 避免拿到结果之后乱用
let message: string = result
// 不能将类型“unknown”分配给类型“string”
console.log(result);

void类型

void通常来指定一个函数没有返回值的,那么它的返回值就是void类型

另外,这个函数可以返回 null,undefined

一般都不写的,因为没有返回值默认推断就是void

function sum(num1: number, num2: number): void {
console.log(num1 + num2); // 这里写不写void都一样的
}
sum(20, 30)

never类型

表示永远不会发生值的类型

never表示函数用于执行不到返回值那一步(抛出异常或死循环)的返回值类型

而void是函数没有返回值,可以返回null,undefined

function foo() {
// 死循环
while(true) {

}
}

function bar() {
throw new Error() // 抛出异常
}

never 有什么应用场景?

// function handleMessage(message: string | number ) {
function handleMessage(message: string | number | boolean ) {
switch (typeof message) {
case 'string':
console.log('string方式处理message');
break
case 'number':
console.log('number方式处理message');
break
case 'boolean':
console.log('boolean方式处理message');
break
default:
// 默认不会执行到返回值那一步,所以如果你没有对应的处理逻辑,就会报错
const check: never = message
}
}

handleMessage("abc")
handleMessage(123)

// 这时候有人想要传入 boolean类型
handleMessage(true)
// 但发现报错了, 然后就给函数参数加上boolean类型
// 然后就不报错了,但是函数里面并没有处理boolean参数的逻辑,他并不知道
// 如果, 加上default那一段,就会报错
// 这时候这个人就知道里面需要有boolean的处理逻辑,然后就去加上

tuple类型

tuple 是元组类型,元组中每个元素都有自己特定的类型,根据索引值获取到的值可以确定对应的类型

const info: [string, number, number] = ["xxx", 18, 1.88]

const name = info[0]
console.log(name.length); // 3

而数组通常建议存放相同类型的值

tuple应用场景

tuple通常可以作为返回的值,在使用的时候会非常的方便

function useState<T>(state: T) {
let currentState = state
const changeState = (newState: T) => {
currentState = newState
}
const info: [string, number] = ['xxx', 18]
const tuple: [T, (newState: T) => void] = [currentState, changeState]
return tuple
}

const [counter, setCounter] = useState(10)
setCounter(1000)
const [title, setTitle] = useState("abc")
const [flag, setFlag] = useState(true)

函数的参数和返回值类型

// 一般可以不写返回值的类型,会自动推断
// function sum(num1: number, num2: number): number {
function sum(num1: number, num2: number) {
return num1 + num2
}

sum(123, 321)

匿名函数的参数

const names = ["aaa", "bbb", "ccc"]
// 我们并没有指定item的类型
// 但是TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型, 这个时候可以不添加的类型注解
names.forEach(function(item) {
console.log(item.split(""));
});

对象类型

如果我们希望限定一个函数接收的参数是一个对象

function printPoint(point: {x: number, y: number}) {
console.log(point.x);
console.log(point.y);
}

printPoint({x: 123, y: 321})

联合类型

function printId(id: number | string) {
// id 可以是number 也可以是 string类型
}

使用联合类型

function printID(id: number | string) {
// 使用联合类型的值时,需要特别的小心
// narrow:缩小
if (typeof id === 'string') {
// 确定id是string类型
console.log(id.toUpperCase());
} else {

}
}

可选类型

对象类型也可以指定哪些属性是可选的,可以在属性后面加一个?

function printPoint(point: {x: number, y:number, z?:number}) {

}

那么这个属性可传可不传

另外,可选类型可以看做是类型和undefined的联合类型

function foo(message?: string) {
console.log(message);
}

foo() // 什么都不传实际上就是代表undefined
foo(undefined)

类型别名

我们可以给对象类型起一个别名,方面我们后续使用

用到了关键字 type

type IDType = string | number
type PointType = {
x: number
y: number
z?: number
}

function printID(id: IDType) {}

function printPoint(point: PointType) {}

类型断言 as

将类型转换为更具体的类型

本来不加类型断言的话,TS只会把el推断为HTMLElement类型

const el = document.getElementById("xxx") as HTMLImageElement
el.src = "url地址"

案例2:Person 是 Student 的父类

function sayHello(p: Person) {
// 不断言的话会报错:类型“Person”上不存在属性“studying”
(p as Student).studying()
}

非空类型断言!

! 用于确定某个标识符是有值的,跳过 ts 在编译阶段时对它的检测

// message 可以是string/undefined
function foo(message?: string) {
// 当然可以直接if判断
// if(message) {

// }

// 但是!更简洁
console.log(message!.length);
}

可选链

实际上是 ES11 增加的特性

?. 操作符,作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行

type Person = {
name: string,
friend?: {
f1?: {
name: string
}
}
}

const info:Person = {
name: 'xxx',
}

// console.log(info.friend.f1); // friend不存在,取不到f1,报错
console.log(info.friend?.f1); // undefined, 不报错
// info.friend存在吗?存在再继续取f1

?? 和 !! 运算符

?? 是 ES11新增的特性

**空值合并操作符 ?? **,是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数, 否则返回左侧操作数

const message = null
const res = message ?? "123"
console.log(res); // "123"

!!操作符,将一个其他类型转换成boolean类型,类型Boolean(变量)

const message = ""
let flag1 = Boolean(message)
let flag2 = !!message

console.log(flag1); // false
console.log(flag2); // false

字面量类型

字面量也可以当做类型

let msg:"hello" = "hello" // 但是msg的值只能是"hello"
msg = "asd" // 报错

那有什么意义呢?可以将多个类型联合在一起

type Alignment = 'left' | 'right' | 'center'

function changeAlign(align: Alignment) {
console.log('修改方向:', align);
}

changeAlign("center") // 只能传入定义的三个字面量类型

字面量推理

下面的代码,默认情况下info 进行类型推断的时候,method是string类型

加上as const 后,methods就是"GET"字面量类型

const info = {
url: "https://hillyee.github.io",
method: "GET"
} as const // 加上as const 后,methods就是"GET"字面量类型

function request(url: string, method: "GET" | "POST") {
console.log(url, method);
}

request(info.url, info.method) // https://hillyee.github.io GET
// 默认:类型“string”的参数不能赋给类型“"GET" | "POST"”的参数。

类型缩小

Type Narrowing 类型缩小

可以通过类似于 typeof padding === “number” 的判断语句,来改变TypeScript的执行路径

在给定的执行路径中,缩小比声明时更小的类型,这个过程称之为 缩小

而我们编写的typeof padding === "number 可以称之为类型保护

常见的类型保护:

  • typeof

    type IDType = number | string
    function printID(id: IDType) {
    // 这外面使用id是 IDtype 类型
    if (typeof id === 'string') {
    // 这里面确认id是string类型
    console.log(id.toUpperCase());
    } else {
    // 确认是number类型
    }
    }
  • 平等缩小(=== == !== !=/switch)

    type Direction = "left" | "right" | "top" | "bottom"
    function printDirection(direction: Direction) {
    // 1.if判断
    // if (direction === 'left') {
    // console.log(direction)
    // } else if ()

    // 2.switch判断
    switch (direction) {
    case 'left':
    console.log(direction)
    break;
    // case ...
    }
    }
  • instanceof

    class Student {}
    class Teacher {}

    function work(p: Student | Teacher) {
    if (p instanceof Student) {

    } else {

    }
    }
  • in

    属性是否存在某对象上

    type Fish = {
    swimming: () => void
    }

    type Dog = {
    running: () => void
    }

    function walk(animal: Fish | Dog) {
    if ('swimming' in animal) {
    } else {
    animal.running()
    }
    }
    const fish:Fish = {
    swimming() {}
    }
    walk(fish)

TS函数类型

  1. 定义常量时,编写函数的类型

    (num1: number, num2: number) => number 就是一个函数类型,并接收两个参数num1,num2,并且都是number类型

    type AddFnType = (num1: number, num2: number) => number
    const add: AddFnType = (a1: number, a2: number) => {
    return a1 + a2
    }
  2. 函数作为参数时,在参数中如何编写类型?

    function foo() {}

    type FooFnType = () => void
    function bar(fn: FooFnType) {
    fn()
    }

    bar(foo)
  3. 参数的可选类型

    function foo(x: number, y?: number) {} // y可选
  4. 默认参数

    function foo(x: number, y: number = 6) {}
  5. 剩余参数

    将一个不定数量的参数放到一个数组中

    function sum(...nums: number[]) {
    let total = 0
    for (const num of nums) {
    total += num
    }
    return total
    }

this类型

当this不确定的时候,通常TS会要求我们明确的指定this的类型

如果不指定的话,非常不安全,因为有可能直接调用函数或者通过别的对象来调用函数

type thisType = { name: string }
function eating(this: thisType, message: string) {
console.log(this);
console.log(this.name + " eating", message);
}

const info = {
name: "xxx",
eating: eating
}

// 隐式绑定
info.eating("asd") // this是info

// 显式绑定
eating.call({name: "kkk"}, "hehehe")
// { name: 'kkk' }
// kkk eating hehehe

函数的重载

函数的重载在实际开发也不是必须要用的,如果本来可以用联合类型简单实现的话,优先选择联合类型

例如有一个需求,希望对字符串和数字类型进行相加

function add(a1: number | string, a2: number | string) {
if (typeof a1 === "number" && typeof a2 === "number") {
return a1 + a2
} else if (typeof a1 === "string" && typeof a2 === "string") {
return a1 + a2
}

// return a1 + a2
// TS 会把 string | number 当做是一个类型
// 运算符“+”不能应用于类型“string | number”和“string | number”
}

add(10, 20)

以上通过联合类型的方式实现有两个缺点:

  • 进行很多的逻辑判断(类型缩小)
  • 返回值的类型依然不确定

函数的重载是什么?

函数的名称相同,但是参数不同的几个函数就是函数的重载,并且是没有函数执行体的

// 构成函数重载
function add(num1: number, num2: number):number
function add(num1: string, num2: string):string

// 函数的实现
// 如果有函数重载,执行体是不能直接被调用的
function add(num1: any, num2: any): any {
// 如果是 string 就返回长度相加
if (typeof num1 === 'string' && typeof num2 === "string") {
return num1.length + num2.length
}
return num1 + num2
}

const res1 = add(10, 20) // 先找到函数的声明 再找执行体
const res2 = add("aaa", "bbb")
console.log(res1); // 30
console.log(res2); // 6

// add({name: "xxx"}, {age: 18})

以上案例确实使用函数重载实现更方便,所以可以选择函数重载

TS类的使用

这部分,实际开发中相对用的少一点,所以笔记暂时记的比较粗糙

类的定义

class Person {
name: string
age: number

constructor(name: string, age: number) {
this.name = name
this.age = age
}
eating() {}
}

类的继承 extends super 关键字

class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eating() {}
}

class Student extends Person {
sno: number
constructor(name: string, age: number, sno: number) {
super(name, age)
this.sno = sno
}
}

类的多态

不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现

类的成员修饰符

  1. public

    共有的,默认编写的属性就是public

  2. private

    仅在同一类中可见

    class Person {
    private _name: string = ""

    constructor(name: string) {
    this._name = name
    }

    // 访问器setter/getter
    set name(newName) {
    this._name = newName
    }
    // getter
    get name() {
    return this._name
    }
    }

    其中 setter/getter 是访问器属性,这样外界就可以存储

    const p = new Person("xxx")
    p.name // 会调用get访问器
    p.name = "kkk" // set
  3. protected

    仅在类自身及子类中可见、受保护的属性和方法

只读属性readonly

只读属性是可以在构造器中赋值, 赋值之后就不可以修改

属性本身不能进行修改, 但是如果它是对象类型, 对象中的属性是可以修改

class Person {
readonly name: string
age?: number
constructor(name: string) {
this.name = name
}
}

const p = new Person("xxx")
p.name = 'kkk' // 报错

静态成员

通过关键字static来定义,直接通过类调用

class Student {
static time: string = "20:00"
static attendClass() {
console.log('去上课');
}
}

console.log(Student.time);
Student.attendClass()

抽象类abstract

抽象类:

  • 以abstract 声明的类是抽象类
  • 抽象类和其他类区别不大,但是不能被实例化(不能通过new调用)
  • 抽象类就是专门用来被继承的类

抽象方法:没有具体实现(没有方法体),抽象方法必须存在于抽象类中

function makeArea(shape: Shape) {
return shape.getArea()
}

abstract class Shape {
abstract getArea(): number
}

class Rectangle extends Shape {
private width: number
private height: number

constructor(width: number, height: number) {
super()
this.width = width
this.height = height
}

// 重写方法
getArea(){
return this.width * this.height
}
}

const rectangle = new Rectangle(20, 30)
makeArea(rectangle)

类的类型

类本身可以作为一个类型

class Person {
name: string = '123'
}

const p = new Person()
const p1: Person = { // p1的类型是Person类,所以必须要传name
name: 'xxx'
}

TS接口的使用

除了可以通过type开声明一个对象类型,还可以通过接口来声明

interface Point {
x: number
y: number
}

另外,接口中也可以定义可选属性,只读属性

interface IInfoType {
readonly name: string
age?: number
}

索引类型

interface IndexLanguage {
[index: number]: string
}

const frontLanguage: IndexLanguage = {
0: "HTML",
1: "CSS",
2: "JavaScript",
3: "Vue"
}

函数类型

用过接口interface来定义函数类型

interface CalcFunc {
(num1: number, num2: number):number
}

const add: CalcFunc = (num1, num2) => {
return num1 + num2
}

当然还是推荐使用类型别名来定义函数

type CalcFunc = (num1: number, num2: number) => number

接口继承

接口和类一样可以进行继承

interface ISwim {
swimming: () => void
}

interface IRunning {
running: () => void
}

interface IPerson extends ISwim, IRunning {

}

const action: IPerson = {
swimming() {},
running() {}
}

接口的实现

implements 用于指定 class 满足某个接口,而且类可以实现多个接口

不是很懂

面向接口开发

interface ISwim {
swimming: () => void
}

interface IRun {
running: () => void
}

class Person implements ISwim, IRun {
swimming() {}
running() {}
}


function swim(swimmer: ISwim) {
swimmer.swimming()
}

const p = new Person()
swim(p)

交叉类型

一种类型合并,表示需要满足多个类型的条件

type MyType = number & string

interface 和 type 区别

interface可以重复对某个接口来定义属性和方法

而type定义的是别名,别名是不能重复的

字面量赋值

interface IPerson {
name: string
age: number
height: number
}

function printInfo(person: IPerson) {
console.log(person);
}

// printInfo({
// name: "xxx",
// age: 18,
// height: 1.88,
// address: "广州市" // 报错
// })

const info = { // 定义字面量
name: "why",
age: 18,
height: 1.88,
address: "广州市"
}

printInfo(info) // 再赋值就不会报错

这是因为TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制。

但是之后如果我们是将一个 变量标识符赋值给其他的变量时,会进行freshness擦除操作

TS枚举类型

枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型

枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型

定义枚举类型的关键字:enum

enum Direction {
LEFT,
RIGHT,
TOP,
BOTTOM
}

function turnDirection(direction: Direction) {
switch (direction) {
case Direction.LEFT:
console.log("改变角色的方向向左")
break;
case Direction.RIGHT:
console.log("改变角色的方向向右")
break;
case Direction.TOP:
console.log("改变角色的方向向上")
break;
case Direction.BOTTOM:
console.log("改变角色的方向向下")
break;
default:
const foo: never = direction;
break;
}
}

TS泛型

非常重要!

基本使用

简单来说就是,类型参数化

类型决定在调用函数的时候

基本使用:多加一个<Type>参数来接收类型

function sum<Type>(num1: Type):Type {
return num1
}

sum<number>(10)
sum<string>("123")
sum<{name: string}>({name: 'xxx'})

还有一种调用方式,类型推导

sum(50) // 那么类型Type就是字面量50

另外,还可以传入多个类型

function foo<T, E, O>(arg1: T, arg2: E, arg3: O, ...args: T[]) {
// ...args: T[] 是剩余参数,放到一个数组,只能选择前面<>定义的类型,
}

foo<number, string, boolean>(10, "aaa", true)

开发时常用的名称:

T:Type的缩写,类型

K、V:key和value的缩写,键值对

E:Element的缩写,元素

O:Object的缩写,对象

泛型接口

定义接口中使用泛型

interface IPerson<T> {
name: T
}

const p:IPerson<string> = {
name: 'xx',
}

泛型类

定义类使用泛型

class Person<T1, T2> {
name: T1
age: T2
constructor(name: T1, age: T2) {
this.name = name
this.age = age
}
}

// 类型推断
let p1 = new Person("kkk", 20)

// 自己定义类型
let p2 = new Person<string, number>('xxx', 18)
let p3:Person<string, number> = new Person("aaa", 21)

泛型约束

给类型参数一点约束

关键字 extends

interface ILength {
length: number
}

function getLength<T extends ILength>(arg: T) {
return arg.length
}

// 传入的参数必须有length属性
getLength("aaa")
getLength(["aaa", "bbb"])
getLength({length: 100})

TS其他内容

模块化开发

TS有两种方式控制作用域

模块化

支持ES Module,CommonJS

image.png

命名空间namespace

是将一个模块内部再进行作用域的划分,防止一些命名 冲突的问题

// 为了其他文件能使用,这里还要导出
export namespace time {
// 内部要export导出,才能在这个ts模块中使用
export function format(time: string) {
return "2022-4-13"
}

// 其他的逻辑
export let name: string = "aaa"
}

export namespace price {
function format(price: number) {
return "99.99"
}
}

TS早期的东西,个人还是选择模块化

类型的查找

在之前,我们除了自己编写类型,还有用到一些其他的类型,比如说

document.getElementById("image") as HTMLImageElement

HTMLImageElement 类型来自哪里呢?

首先我们需要知道一种ts文件:.d.ts为后缀名的文件

  • 这种文件是用来做类型的声明的(declare)。它仅仅用来做类型检测,告诉typescript我们有哪些类型
  • 这种文件是不需要转成js文件来运行的

那么typescript会在哪里查找我们的类型声明呢?

有三种:

  • 内置类型声明

    typescript自带的,帮助我们内置了JS运行时的一些标准化API的声明文件

    比如如Math、Date等内置类型,也包括DOM API,比如Window、Document等

    内置类型声明通常在我们安装typescript环境中会带有

    github:https://github.com/microsoft/TypeScript/tree/main/lib

  • 外部定义类型声明

    通常是我们使用一些库时,需要的一些类型声明

    这些库有两种类型声明方式

    1. 在自己库中进行类型声明(编写.d.ts文件),比如axios
    2. 通过社区的一个公有库DefinitelyTyped存放类型声明文件

    github链接:

    该库的GitHub地址:https://github.com/DefinitelyTyped/DefinitelyTyped/

    该库查找声明安装方式的地址:https://www.typescriptlang.org/dt/search?search=

    比如我们需要安装react的类型声明,就可以去查找安装方式

  • 自定义类型声明

    比如我们使用的第三方库是一个纯的JavaScript库,没有对应的声明文件;比如lodash

    这时候我们要自己声明类型文件:

    任意一个项目文件夹下定义.d.ts 文件,ts会自己找到的

    声明模块关键字:declare

    // 声明模块
    declare module 'lodash' {
    export function join(arr: any[]): void
    }

声明变量-函数-类

.d.ts 文件中声明

declare let myName: string
declare let myAge: number

// 只是声明类型, 不需要执行体
declare function myFoo(): void

declare class Person {
name: string
age: number
constructor(name: string, age: number)
}

在其他地方使用:

let myName = "xxx"
let myAge = 18

function myFoo() {}

function Person(name, age) {
this.name = name
this.age = age
}

let p = new Person("xxx", 18)

声明模块

声明模块的语法: declare module ‘模块名’ {}。

在声明模块的内部,可以通过export导出对应库的类、函数等

declare module 'lodash' {
export function join(arr: any[]): void
}

声明文件

文件会被当成模块使用,然后就可以引入

declare module '*.jpg'
declare module '*.jepg'
declare module '*.png'

在别的地方import使用

import img from './img/xxx.jpg'

声明命名空间

比如在index.html中直接引入jQuery

然后在声明文件中(.d.ts

declare namespace $ {
export function ajax(settings: any):any
}

然后就可以在别的文件使用

$.ajax({...})