Bootstrap

TypeScript

TypeScript

Typescript是一个JavaScript的超集,即Type+Script,为JS添加类型支持。

Typescript属于静态类型编程语言,JS属于动态类型编程语言

JS类型(执行期做类型检查):需等到代码真正执行才能发现错误(晚)

TS类型(编译期做类型检查):在代码编译时即可发现错误(早)→减少找BUG、改BUG的时间

在这里插入图片描述

TS初体验

安装编译TS的工具包

目的:Node.js/浏览器,只认识 JS 代码,不认识 TS 代码;需先将TS代码转为JS代码

typescript 包:实现了 TS -> JS 的转化,用来编译 TS 代码的包

安装命令:

npm i -g typescript
//验证是否安装成功
tsc-v

内在机制:

在这里插入图片描述

编译并运行 TS 代码

1.创建 hello.ts 文件

console.log('hello ts');
let age: number = 15
console.log(age);

2.将 TS 编译为 JS:在终端中输入命令,tsc hello.ts→同级目录会出行同名JS文件

console.log('hello ts');
var age = 15;
console.log(age);

3.执行JS代码:node hello.js

在这里插入图片描述

简化运行TS步骤

问题:每次修改代码后,需重复执行两个命令→麻烦

简化方式:使用ts-node 包→直接在 Node.js 中执行 TS 代码

安装命令:

npm i -g ts-node

使用方式:

ts-node hello.ts

注意:在内部将TS -> JS,然后,再运行 JS 代码

TypeScript 常用类型

类型注解

//:number 就是类型注解
let age: number = 18

作用:为变量添加约束类型→约定什么类型,就只能给变量赋值该类型

在这里插入图片描述

常用类型分类

1.JS 已有类型

  • 原始类型:number/string/boolean/null/undefined/symbol。
  • 对象类型:object(包括,数组、对象、函数等对象);

2.TS 新增类型

  • 联合类型、自定义类型(类型别名)、接口、元组、字面量类型、枚举、void、any 等

原始类型

number/string/boolean/null/undefined/symbol

完全按照 JS 中类型的名称来书写

let age: number = 18
let myName: string = '小张'
let isLoading: boolean = false
let a: null = null
let b: undefined = undefined
let s: symbol = Symbol()

数组类型

// 数字类型
let numbers: number[] = [1,2,3,4]
// let numbers1: Array<number> [1,2,3,4]
// 布尔值类型数组
let b: boolean[] = [true, false]
//联合类型:
//添加小括号, 表示;首先是数组,然后,这个数组中能够出现number或string类型的元素
let arr: (number | string)[] = [1,'a',2,'b',3,'c']
// 不添加小括号,表示:arr1既可以是number类型,又可以是string[]
// let arr1: number | string[] = ['a', 'b']
// let arr1: number | string[] = 123

类型别名(自定义类型)

通过类型别名,简化该类型的使用

// 改造:类型别名
type CustomArray = (number | string)[]

// let arr: (number | string)[] = [1,'a',2,'b',3,'c']
let arr1: CustomArray = [1,'a',2,'b',3,'c']
// let arr1: (number | string)[] = [1,'x',2,'y',3,'z']
let arr2: CustomArray = [1,'x',2,'y',3,'z']

函数类型

函数指定类型的两种方式:

1.单独指定参数、返回值类型

2.同时指定参数、返回值类型

// 1.单独指定参数、返回值类型
// function add(num1: number, num2:number) :number {
//   return num1 + num2
// }
// console.log(add(1,2))

// const add1 = (num1:number, num2:number ): number => {
//   return num1 + num2
// }
// console.log(add1(2,6));

// 2.同时指定参数、返回值类型
const add: (num1:number, num2:number) => number =(num1, num2) => {
  return num1 + num2
}
console.log(add(6,9))

3.函数如果没有返回值,则返回值类型为void

function greet(name: string): void {
  console.log('hello', name)
}
greet('lucy')

4.可选参数

// 可选参数可以位于必选参数后面,但比选参数不能位于可选参数后面
function mySlice(start?: number, end?: number): void {
  console.log('起始索引:', start, '结束索引:', end);
}
mySlice()
mySlice(1)
mySlice(1,6)

在这里插入图片描述

对象类型

JS对象类型由属性和方法构成;

TS对象类型是描述对象的结构

let person: {
  name:string 
  age:number 
  sayHi(): void 
  greet(name: string): void 
} = {
  name:'小张',
  age:21,
  sayHi() {},
  greet(name) {}
}

可选属性:

function myAxios(config: {url: string; method?: string}) {
  myAxios({
    url: ''
  })
}

接口

1.声明interface(接口)后,直接使用接口名称作为变量的类型

// let person: {name:string; age:number; sayHi(): void; greet(name: string): void } = {
//   name:'小张',
//   age:21,
//   sayHi() {},
//   greet(name) {}
// }
// let person1: {name:string; age:number; sayHi(): void; greet(name: string): void }

// 接口:
interface IPerson {
  name:string 
  age:number 
  sayHi(): void 
  greet(name: string): void 
}
let person: IPerson = {
  name:'小张',
  age:21,
  sayHi() {},
  greet(name) {}
}

let person1: IPerson = {
  name:'小唐',
  age:21,
  sayHi() {},
  greet(name) {}
}

2.interface(接口)和 type(类型别名)的对比:

相同:都可给对象指定类型

不同:接口,只能为对象指定类型;类型别名可为任意类型指定别名

3.接口继承

interface Point2D { x:number; y: number }
// interface Point3D { x:number; y: number; z:number }

// 使用继承 实现复用:
interface Point3D extends Point2D {z:number}

let p3: Point3D = {
  x:9,
  y:8,
  z:10
}

元组(Tuple)

使用场景:确切知道包含多少个元素,以及特点索引对应的类型

// let posiition: number[] = [39,114,55,69]

// 使用元组
// 使用场景:确切地知道包含多少个元素,以及特定索引对应的类型时
let posiition: [number, number] = [39,114]

类型推论

由于类型推论的存在,有些地方,类型注解可省略不写

发生类型推论场景:

1.声明变量并初始化时

2.决定函数返回值时

// 声明变量并立即初始化值,此时,可以省略类型注解
let age = '18'
// age = ''

// 注意:如果声明变量但没有立即初始化值,此时,还必须手动添加类型注解
let a: number

a = 18
// a = ''
// --------------------------------------------
function add (num1:number, num2:number) {
  return num1 + num2
}
add(1,2)
//add(false,5)

类型断言

在这里插入图片描述

使用as实现类型断言,使alink类型变得更加具体→即可访问到a标签特有属性和方法

// const alink = document.getElementById('link')
// alink.href

// 类型断言
const aLink = document.getElementById('link') as HTMLAnchorElement
aLink.href

技巧:查看对应标签类型的方法:

在浏览器控制台,通过console.dir() 打印 DOM 元素→属性列表最后面,即显示标签元素

字面量类型

// 类型为string
// str是一个变量(let),值可以是任意字符串
let str = 'Hello TS'
// 类型为 'hello TS'
// str2是一个常量,它的值不能变化只能是'hello TS'
const str2 = 'hello TS'

// 字面量类型:用来表示一组明确的可选值列表
// 某个特定的字符串、数字、对象也可以作为 TS 中的类型
const str3:'hello TS' = 'hello TS'
let age:18 = 18

// 一般配合联合类型一起使用
function changeDirection (direction: 'up' | 'down' | 'left' | 'right') {}
changeDirection('left')

枚举

// 枚举
// 默认情况下,枚举成员有值,从0开始自增(数字枚举)
// enum Direction { Up, Down, Left, Right}
// function changeDirection(direction: Direction) {
//   console.log(direction)
  
// }
// changeDirection(Direction.Up)

// 成员设置初始值
enum Direction { Up=2, Down=4, Left=6, Right=8}
function changeDirection(direction: Direction) {
  console.log(direction)
  
}
changeDirection(Direction.Up)

字符串枚举

// 枚举可以是数字类型,也可以是字符串类型
enum Direction { 'Up', 'Down', 'Left', 'Right'}
function changeDirection(direction: Direction) {
  console.log(direction)
}
changeDirection(Direction.Up)

枚举的原理说明:枚举不仅作类型,还提供值;会被编译为JS代码

var songs = ['西安', '成都'];
var Direction;
(function (Direction) {
    Direction["Up"] = "UP";
    Direction["Down"] = "DOWN";
    Direction["Left"] = "LEFT";
    Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));
function changeDirection(direction) { }
changeDirection(Direction.Up);

any 类型

不推荐使用any

TypeScript 变为 “AnyScript”→失去 TS 类型保护的优势

typeof

//typeof:用来在 JS 中获取数据的类型
console.log(typeof 'Hello TS') // string

let p = { x: 1, y: 2 }

//可以在类型上下文中引用变量或属性的类型
function formatPoint(point: typeof p) {}
// function formatPoint(point: { x: number; y: number }) {}
formatPoint({ x: 1, y: 100 })

// --
let num: typeof p.x

function add(num1: number, num2: number) {
  return num1 + num2
}
//typeof 只能用来查询变量或属性的类型
// typeof 不能查询函数调用的类型
// let ret: typeof add(1, 2)

TypeScript 高级类型

class类

1.不仅提供了class 的语法功能,也作为一种类型存在

class Person {
  //实例属性初始化
  age: number
  gender = '男'
  // gender: string = '男'
}

const p = new Person()

p.age
p.gender

2.构造函数

class Person {
  //成员初始化后,才可通过this.age、this.gender访问实例成员
  age: number
  gender: string

  //需为构造函数指定类型注解→否则会被隐式推断为any
  //构造函数不需要返回值类型
  constructor(age: number, gender: string) {
    // 实例属性初始化
    this.age = age
    this.gender = gender
  }
}

const p = new Person(18, '男')
console.log(p.age, p.gender)

3.实例方法

class Point {
  x = 1
  y = 2

  scale(n: number) {
    this.x *= n
    this.y *= n
  }
}

const p = new Point()

p.scale(10)

console.log(p.x, p.y)//10,20

4.继承父类

class Animal {
  move() {
    console.log('走两步')
  }
}
// 通过extends实现继承
// 继承之后子类则具备父类所有的属性和方法
class Dog extends Animal {
  name = '二哈'

  bark() {
    console.log('旺旺!')
  }
}

const d = new Dog()
d.move()
d.bark()
console.log(d.name)

5.实现接口

interface Singale {
  sing(): void
  name: string
}
// 通过 implements 关键字让 class 实现接口
class Person implements Singale {
  name = 'jack'

  sing() {
    console.log('你是我的小呀小苹果')
  }
}

6.成员可见性-public

// 父类
// public:公有的、公开的;在任何地方都可被访问到
//public 是默认可见性,所以,可以直接省略

class Animal {
  public move() {
    console.log('走两步')
  }
}

const a = new Animal()
a.move()

// 子类
class Dog extends Animal {
  bark() {
    console.log('旺旺!')
  }
}

const d = new Dog()
d.move()

7.成员可见性-protected

// 父类
class Animal {
  // 这个方法是受保护的
  // 不可在实例对象中访问,只能在类和子类内部通过this进行访问
  protected move() {
    console.log('走两步')
  }

  run() {
    this.move()
    console.log('跑起来')
  }
}

const a = new Animal()
// a.move()

// 子类
class Dog extends Animal {
  bark() {
    this.move()
    console.log('旺旺!')
  }
}

const d = new Dog()
// d.move()

8.成员可见性-private

// 父类
class Animal {
  // 对于当前类来说是可见的
  private __run__() {
    console.log('Animal 内部辅助函数')
  }

  // 受保护的
  protected move() {
    this.__run__()
    console.log('走两步')
  }

  // 公开的
  run() {
    this.__run__()
    this.move()
    console.log('跑起来')
  }
}

const a = new Animal()
// a.

// 子类
class Dog extends Animal {
  bark() {
    // 对子类来说不可见
    // this.
    console.log('旺旺!')
  }
}

const d = new Dog()
// 对子类的实例也是不可见的
// d.

9.readonly(只读修饰符)

表示只读,用来防止在构造函数之外对属性进行赋值

/* class Person {
  // 只读属性
  readonly age: number = 18
  constructor(age: number) {
    this.age = age
  }
  // 错误演示:
  // 只能修饰属性,不能用它修饰方法
  // readonly setAge() {
  //   // this.age = 20
  // }
} */

class Person {
  // 只读属性
  // 注意:只要是 readonly 来修饰的属性,必须手动提供明确的类型
  // 若不加类型注解,则会变为字面量类型
  readonly age: number = 18
  constructor(age: number) {
    this.age = age
  }
}

// --

// interface IPerson {
//   readonly name: string
// }

// let obj: IPerson = {
//   name: 'jack'
// }

let obj: { readonly name: string } = {
  name: 'jack'
}
 obj.name = 'rose'//报错→无法为name赋值,因为它是只读属性

类型兼容

TS采用结构化类型系统,类型检查关注的是值所具有的形状

1.语法

// 演示类型兼容性:

// let arr = ['a', 'b', 'c']

// arr.forEach(item => {})
// arr.forEach((item, index) => {})
// arr.forEach((item, index, array) => {})

// 两个类的兼容性演示:
//只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)
class Point {
  x: number
  y: number
}
class Point2D {
  x: number
  y: number
}

const p: Point = new Point2D()

2.更准确写法:对于对象类型来说,成员多的可以赋值给少的

// 两个类的兼容性演示:

class Point {
  x: number
  y: number
}
class Point2D {
  x: number
  y: number
}

const p: Point = new Point2D()

class Point3D {
  x: number
  y: number
  z: number
}

const p1: Point = new Point3D()

// 错误演示
// const p2: Point3D = new Point()

3.接口兼容性

interface Point {
  x: number
  y: number
}
interface Point2D {
  x: number
  y: number
}
interface Point3D {
  x: number
  y: number
  z: number
}

let p1: Point
let p2: Point2D
let p3: Point3D

// 正确:
// p1 = p2
// p2 = p1
// p1 = p3

// 错误演示:
// p3 = p1

// 类和接口之间也是兼容的
class Point4D {
  x: number
  y: number
  z: number
}
p2 = new Point4D()

4.函数兼容性-函数参数个数:参数少的可以赋值给多的

// 1 参数个数: 参数少的可以赋值给参数多的
type F1 = (a: number) => void
type F2 = (a: number, b: number) => void

let f1: F1 = () => {}
let f2: F2 

f2 = f1

// 错误演示:
// f1 = f2

5.函数兼容性-函数参数类型:相同位置的参数类型要相同(原始类型)或兼容(对象类型)

// 2 参数类型: 相同位置的参数类型要相同或兼容

// 原始类型:
// type F1 = (a: number) => void
// type F2 = (a: number) => void

// let f1: F1
// let f2: F2

// f1 = f2
// f2 = f1

// -------------------------

// 对象类型
interface Point2D {
  x: number
  y: number
}
interface Point3D {
  x: number
  y: number
  z: number
}

type F2 = (p: Point2D) => void // 相当于有 2 个参数
type F3 = (p: Point3D) => void // 相当于有 3 个参数

let f2: F2 = () => {}
let f3: F3

f3 = f2

// f2 = f3

6.返回值类型:只关注返回值类型本身即可

// 3 返回值类型,只需要关注返回值类型本身即可

// 原始类型:
type F5 = () => string
type F6 = () => string

let f5: F5
let f6: F6

// f6 = f5
// f5 = f6

// 对象类型:
// 返回内容都是对象类型,此时按照对象自身的兼容性来理解即可
type F7 = () => { name: string }
type F8 = () => { name: string; age: number }

let f7: F7
let f8: F8

f7 = f8

// 错误演示
// f8 = f7

交叉类型

1.类似于接口继承(extends),用于组合多个类型为一个类型(常用于对象类型)

interface Person {
  name: string
  say(): number
}
interface Contact {
  phone: string
}

type PersonDetail = Person & Contact

//新的类型 PersonDetail 就同时具备了 Person 和 Contact 的所有属性类型。
let obj: PersonDetail = {
  name: 'jack',
  phone: '133....',
  say() {
    return 1
  }
}

2.交叉类型(&)和接口继承(extends)的对比

相同:都可实现对象类型的组合

不同:对于同名属性之间,处理类型冲突的方式不同
在这里插入图片描述

注意:以上代码,接口继承会报错(类型不兼容);交叉类型不报错

可理解为:
在这里插入图片描述

泛型

在保证类型安全前提下,让函数可以与多种类型一起使用

1.基本语法:

// 1.使用泛型来创建一个函数:

function id<Type>(value: Type): Type {
  return value
}

// 2.调用泛型函数:

// 2.1 以 number 类型调用泛型函数
const num = id<number>(10)

// 2.2 以 string 类型调用泛型函数
const str = id<string>('a')
const ret = id<boolean>(false)

2.简化泛型函数的调用

可以省略 <类型> 来简化泛型函数的调用→TS内部采用类型参数推断机制,可自行推断

// 1.使用泛型来创建一个函数:

function id<Type>(value: Type): Type {
  return value
}

// 2.调用泛型函数:

// 2.1 以 number 类型调用泛型函数
let num1 = id(100)
// 2.2 以 string 类型调用泛型函数
let str1 = id('abc')

3.泛型约束

为泛型添加约束来收缩类型→缩窄类型取值范围

将原来可以代表任何类型的type缩窄到几个类型当中

方法:

1)指定更加具体的类型

// 将类型修改为type[]→数组一段存在length属性
function id<Type>(value: Type[]): Type[] {
  value.length
  return value
}

2)添加约束

interface ILength {
  length: number
}

function id<Type extends ILength>(value: Type): Type {
  value.length
  return value
}

// 传入的类型必须具有 length 属性
id(['a', 'c'])
id('abc')
id({ length: 10, name: 'jack' })

// 错误演示
// id(123)

4.添加类型约束(使用keyof):第二个类型变量受第一个类型变量约束

// key只能是type中存在的属性和名称
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key]
}

getProp({ name: 'jack', age: 18 }, 'age')
getProp({ name: 'jack', age: 18 }, 'name')

// 补充:(了解)
getProp(18, 'toFixed')
getProp('abc', 'split')
getProp('abc', 1) // 此处 1 表示索引
getProp(['a'], 'length')
getProp(['a'], 1000)

console.log('object'[1]) // b

// 错误演示:
// getProp({ name: 'jack', age: 18 }, 'name1')

5.泛型接口

1.基本语法

interface IdFunc<Type> {
  id: (value: Type) => Type
  ids: () => Type[]
}

let obj: IdFunc<number> = {
  //id 方法的参数和返回值类型都是 number
  id(value) {
    return value
  },
  //ids 方法的返回值类型是 number[]
  ids() {
    return [1, 3, 5]
  }
}

2.泛型接口-数组

JS中的数组在TS中就是一个泛型接口
在这里插入图片描述

6.泛型类

class 也可以配合泛型来使用

// class GenericNumber<NumType> {
//   defaultValue: NumType
//   add: (x: NumType, y: NumType) => NumType

//   constructor(value: NumType) {
//     this.defaultValue = value
//   }
// }
// 此时,可以省略 <类型> 不写。因为 TS 可以根据传入的参数自动推导出类型
// const myNum = new GenericNumber(100)
// myNum.defaultValue = 10

// ---------------------------------------------------------------

class GenericNumber<NumType> {
  defaultValue: NumType
  add: (x: NumType, y: NumType) => NumType
}

// 这种情况下,推荐明确指定 <类型>。因为 TS 无法推导出类型
const myNum = new GenericNumber()
myNum.defaultValue = 10

7.泛型工具类型:TS内置的一些常用工具类型,用来简化常用操作

1)Partial

//Partial<type>
//创建一个新类型,将type所有属性设置为可选
interface Props {
  id: string
  children: number[]
}

type PartialProps = Partial<Props>

let p1: Props = {
  id: '',
  children: [1]
}
let p2: PartialProps = {
  id: '',
  children: [1, 3]
}

2)Readonly

interface Props {
  id: string
  children: number[]
}

// Readonly<Type>
// 将所有属性设置为只读
type ReadonlyProps = Readonly<Props>

let p1: ReadonlyProps = {
  id: '1',
  children: [1, 3]
}

p1.id = '2'

在这里插入图片描述

3)Pick

interface Props {
  id: string
  title: string
  children: number[]
}

// Pick<Type, Keys>
// 从 Type 中选择一组属性来构造新类型
//第二个类型变量传入的属性只能是第一个类型变量中存在的属性
type PickProps = Pick<Props, 'id' | 'title'>

4) Record

// Record<Keys,Type>
// 构造一个对象类型,属性键为 Keys,属性类型为 Type
// 1 表示对象有哪些属性 2 表示对象属性的类型
type RecordObj = Record<'a' | 'b' | 'c', string[]>

// type RecordObj = {
//   a: string[]
//   b: string[]
//   c: string[]
// }

let obj: RecordObj = {
  a: ['a'],
  b: ['b'],
  c: ['c']
}

索引签名类型

使用场景:没法直接去确定对象中有哪些属性和方法时

key只是一个占位符,可换成任意合法变量名称

注意:JS中对象({})的建是string类型

// 通过索引的写法,能够让对象接收任意的属性
interface AnyObject {
  [key: string]: number
}

let obj: AnyObject = {
  a: 1,
  abc: 124,
  abcde: 12345
}

// --

const arr = [1, 3, 5]
arr.forEach

interface MyArray<Type> {
  [index: number]: Type
}
let arr1: MyArray<number> = [1, 3, 5]
arr1[0]

映射类型

1.根据联合类型创建新类型

type PropKeys = 'x' | 'y' | 'z' | 'a' | 'b'
type Type1 = { x: number; y: number; z: number; a: number; b: number }

// 表示 Key 可以是 PropKeys联合类型中的任意一个
type Type2 = { [Key in PropKeys]: number }

// 错误演示:
// interface Type3 {
//   [Key in PropKeys]: number
// }

2.使用keyof创建

type Props = { a: number; b: string; c: boolean }

type Type3 = { [key in keyof Props]: number }

3.Partial实现原理

type Props = { a: number; b: string; c: boolean }
type PartialProps = Partial<Props>

4.索引查询类型:用来查询属性的类型

type Props = { a: number; b: string; c: boolean }

type TypeA = Props['a']

// 模拟 Partial 类型:
type MyPartial<T> = {
  [P in keyof T]?: T[P]
}

type PartialProps = MyPartial<Props>

在这里插入图片描述

5.同时查询多个索引类型

type Props = { a: number; b: number; c: boolean }

// 其他使用方式:
// 获取a和b属性的类型
type TypeA = Props['a' | 'b']//string | number

// 直接获取Props中所有属性的类型
type TypeB = Props[keyof Props]//string | number | boolean

TypeScript 类型声明文件

在项目开发中使用第三方库时,几乎都有相应的TS类型,即类型声明文件

类型声明文件:用来为已存在的 JS 库提供类型信息

TS 的两种文件类型

1…ts 文件(代码实现文件)

  • 既包含类型信息又可执行代码
  • 可以被编译为 .js 文件,然后,执行代码
  • 用途:编写程序代码的地方

2…d.ts 文件(类型声明文件)

  • 只包含类型信息的类型声明文件

  • 不会生成 .js 文件,仅用于提供类型信息

  • 用途:为 JS 提供类型信息

    // 类型声明文件
    
    // 类型
    type Props1 = { x: number; y: number }
    
    // 错误演示:因为 .d.ts 文件中,不能出现可执行代码(代码实现)
    // 可执行代码
    // function add1(num1: number, num2: number) {
    //   return num1 + num2
    // }
    // console.log(add1(1, 5))
    

声明文件使用说明

1.使用已有的类型声明文件

1)内置类型声明文件:

TS 为 JS 运行时可用的所有标准化内置 API 都提供了声明文件

let arr = [1, 3, 5]
arr.forEach

document.querySelector

window

ctrl+鼠标左键→自动跳转到 lib.es5.d.ts 类型声明文件中
在这里插入图片描述

window、document 等 BOM、DOM API 也都有相应的类型声明

ctrl+鼠标左键→自动跳转到lib.dom.d.ts文件
在这里插入图片描述

2)第三方库的类型声明文件:

几乎所有常用的第三方库都有相应的类型声明文件

第三方库类型声明文件存在形式

  • 库自带类型声明文件:比如,axiost.md
    在这里插入图片描述

TS 就会自动加载库自己的类型声明文件,以提供该库的类型声明

  • 由 DefinitelyTyped 提供
  1. DefinitelyTyped 是一个 github 仓库,用来提供高质量 TypeScript 类型声明
  2. 可通过npm/yarn 来下载该仓库提供的 TS 类型声明包,包的名称格式为:@types/*
    在这里插入图片描述

2.创建自己的类型声明文件

1.项目内共享类型:若多个.ts共有同一个类型,此时可创建**.ts文件**提供该类型,实现类型共享

1)创建 index.d.ts 类型声明文件

2)创建需要共享的类型,并使用 export 导出

3)在需要使用共享类型的 .ts 文件中,通过 import 导入即可

index.d.ts

type Props = { x: number; y: number }

export { Props }

a.ts

// a.ts
import { Props } from './index'

// type Props = { x: number; y: number }

let p1: Props = {
  x: 1,
  y: 2
}

b.ts

// b.ts
import { Props } from './index'

// type Props = { x: number; y: number }

let p2: Props = {
  x: 10,
  y: 22
}

2.为已有JS文件提供类型声明

1)在将 JS 项目迁移到 TS 项目时,为了让已有的 .js 文件有类型声明

2)成为库作者,创建库给其他人使用

utils.js

let count = 10
let songName = '痴心绝对'
let position = {
  x: 0,
  y: 0
}

function add(x, y) {
  return x + y
}

function changeDirection(direction) {
  console.log(direction)
}

const fomartPoint = point => {
  console.log('当前坐标:', point)
}

export { count, songName, position, add, changeDirection, fomartPoint }

utils.d.ts

// 为 utils.js 文件来提供类型声明
// declare:为已存在的变量声明类型

declare let count: number
declare let songName: string
// 明确是TS类型,可以省略declare,如interface、type
interface Point {
  x: number
  y: number
}
declare let position: Point

declare function add(x: number, y: number): number
declare function changeDirection(
  direction: 'up' | 'down' | 'left' | 'right'
): void

type FomartPoint = (point: Point) => void
declare const fomartPoint: FomartPoint

// 注意:类型提供好以后,需要使用 模块化方案 中提供的
//      模块化语法,来导出声明好的类型。然后,才能在
//      其他的 .ts 文件中使用
export { count, songName, position, add, changeDirection, fomartPoint, Point }

index.ts(使用)

import { count, songName, add, Point } from './utils'

type Person = {
  name: string
  age: number
}

let p: Partial<Person> = {
  name: 'jack'
}

let p1: Point = {
  x: 10,
  y: 20
}

// console.log('项目启动了')
console.log('count', count)
console.log('songName', songName)
console.log('add()', add(1, 4))

已有JS文件提供类型声明**

1)在将 JS 项目迁移到 TS 项目时,为了让已有的 .js 文件有类型声明

2)成为库作者,创建库给其他人使用

utils.js

let count = 10
let songName = '痴心绝对'
let position = {
  x: 0,
  y: 0
}

function add(x, y) {
  return x + y
}

function changeDirection(direction) {
  console.log(direction)
}

const fomartPoint = point => {
  console.log('当前坐标:', point)
}

export { count, songName, position, add, changeDirection, fomartPoint }

utils.d.ts

// 为 utils.js 文件来提供类型声明
// declare:为已存在的变量声明类型

declare let count: number
declare let songName: string
// 明确是TS类型,可以省略declare,如interface、type
interface Point {
  x: number
  y: number
}
declare let position: Point

declare function add(x: number, y: number): number
declare function changeDirection(
  direction: 'up' | 'down' | 'left' | 'right'
): void

type FomartPoint = (point: Point) => void
declare const fomartPoint: FomartPoint

// 注意:类型提供好以后,需要使用 模块化方案 中提供的
//      模块化语法,来导出声明好的类型。然后,才能在
//      其他的 .ts 文件中使用
export { count, songName, position, add, changeDirection, fomartPoint, Point }

index.ts(使用)

import { count, songName, add, Point } from './utils'

type Person = {
  name: string
  age: number
}

let p: Partial<Person> = {
  name: 'jack'
}

let p1: Point = {
  x: 10,
  y: 20
}

// console.log('项目启动了')
console.log('count', count)
console.log('songName', songName)
console.log('add()', add(1, 4))
;