TypeScript基础

TS编译运行

ts不是在终端运行,是一门中间语言,最终编译为js运行。

手动编译

// 1. ts编译为js
npm i -g typescript
// 查看版本
tsc -v

// 2. ts直接运行,主要用来查看是否报错
npm i -g ts-node
// 查看版本
ts-node -v

1.手动编译ts代码

tsc .\test.ts

2.生成tsconfig.json文件

tsc --init

TypeScript基础_第1张图片

webpack

# 生成package.json文件
npm init -y

# 安装webpack环境
npm i -D webpack webpack-cli

# 安装ts解析
npm i -D ts-loader

# 安装html模板
npm i -D html-webpack-plugin

# 安装webpack本地服务器
npm i -D webpack-dev-server

在根目录下编写webpack.config.js文件

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "bundle.js"
  },
  resolve: {
    extensions: [".ts", ".js", ".cjs", ".json"]
  },
  devServer: {},
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: "ts-loader"
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html'
    })
  ]
}

生成ts配置文件,tsconfig.json

tsc --init

非引用类型

声明的类型称为类型注解(Type Annotation)
let 类型推断为具体类型
const 类型推荐为字面量类型

非引用类型:
number、string、boolean、undefined、null、Symbol、BigInt

// 非引用类型:
// number、string、boolean、undefined、null、Symbol、BigInt
let num:number = 10
let num2:number = 0b110
let num3:number = NaN
let num4:number = Infinity

let flag:boolean = false

let str:string = '123'
let str2:string = "abc"

let unde:undefined = undefined

let nu:null = null

// 表示唯一,即使内容一样也表示唯一
let s1:symbol = Symbol('k1')
let s2:symbol = Symbol('k1')
let person = {
    [k1]:'v1',
    [k1]:'v2'
}

// 字面量类型
var ENV:"production"|"development"|"test"='development'
let age:99|100 = 99

引用类型

引用类型:object、array、function

数组

// 只能空数组
let arr1:[] = []
let arr2:number[] = [1,2,3]
let arr3:Array<number> = [1,2,3]

// 数组内有字符串和数字类型
var arr:(string|number)[] = ['cjc',999]

// 字符串数组或数字数组
var arr2: string[] | number[] = ['a', 'b']
var arr3: string[] | number[] = [1, 2]

// 元祖,顺序和类型都要满足
// 最后任意类型且可有可无
var arr4: [string, number, any?] = ['cjc', 999, true]

// 不定参数
var arr4: [string, number, ...(number|string)[]] = ['cjc', 999, 1,2,3]

对象

// 空对象
let obj:object = {}
let obj2:{} = {name:'cjc'}
let obj3:{name:string,age:number} = {name:'cjc',age:999}

// 键名数字类型
var obj4: { [propNmae: number]: string } = { 1: 'a', 2: 'b' }

// 可选 ?
var obj5: { x: number, y?: boolean } = { x: 1 }

函数

函数定义方式

// 1.声明式函数定义
function sumFun(a: number, ...args: number[]): number {
  return a + args.reduce((preVal: number, curVal: number) => {
    return preVal + curVal
  })
}
console.log(sumFun(1, 2, 3)); //6

// 2.函数变量
let foo2: (a: string) => string = function (a) {
  return a
}

// 3.匿名函数
// 一般匿名函数不用指定类型
callback(function(){})

// this处理
function foo3(this:void,a:number){}
foo3(1)

函数类型

方式1 函数类型表达式

  • 定义函数类型若有参数,则必须携带形参名
// 定义函数的类型
// 必须携带形参名
type calcFnType = (num1: number, num2: number) => number

function calc(calcFn: calcFnType) {
  let res = calcFn(1, 2)
  return res
}

function add(a: number, b: number) {
  return a + b
}

function minus(a: number, b: number) {
  return a - b
}

let res = calc(add)
// 3
console.log(res);

let res2 = calc(minus)
// -1
console.log(res2);

方式2 调用签名(call signatures)
函数本身也是对象类型,可以给函数指定类型的同时添加属性

  • 定义函数类型若有参数,则必须携带形参名
  • 函数类型语法 (形参名:类型) : 类型
interface IFoo {
  name: string,
  age: number,
  (num: number): number
}

const foo: IFoo = (num: number): number => {
  return 1
}

foo.name = 'ccc'
foo.age = 999

函数重载

函数重载:函数名相同,形参不同

//输入数字 `123` 的时候,输出反转的数字 `321`,输入字符串 `'hello'` 的时候,输出反转的字符串 `'olleh'`

// 1.函数重载签名
function reverse(x: number): number;
function reverse(x: string): string;

// 2.通用函数实现
function reverse(x: any): any {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

any、unknow

any、unknow都能赋值任何类型的值
any类型进行任何操作
unknow类型不能进行任何操作,类型缩小(例如typeof)后才能进行对应类型的操作

// 1.any
let a: any = 123
let b: string = a

// 2.unknow
// unknow比any更安全,unknow类型只能赋值给unknow或any
let a2: unknown = 123
//不能将类型“unknown”分配给类型“string”
// let b2:string = a2
let b2: any = a2

void

函数没有返回值时,返回void类型

type execFunType = (...args: any[]) => void
function delayFun(fn: execFunType) {
  setTimeout(() => {
    fn('ccc', 999)
  }, 1000);
}

delayFun((name, age) => {
  console.log(name);
  console.log(age);
})

never

never类型不能有任何值
应用场景:

  1. 函数中死循环或抛出异常,此时函数没有返回值。
  2. 封装框架或工具时,增加健壮性

没有对boolean类型的处理,报错:
TypeScript基础_第2张图片
增加对boolean的处理:

function foo(msg: string | number | boolean) {
  switch (typeof msg) {
    case 'string':
      console.log(msg.length);
      break;
    case "number":
      console.log(msg);
      break;
    case "boolean":
      break;
    default:
      const check: never = msg
      break;
  }
}

tuple元祖

一般数组中存放相同的数据类型,元祖中可以存放不同的数据类型

const stu:[string,number] = ['CCC',999]
const name = stu[2]

应用场景:用于函数的返回值

function useState<T>(state: T): [T, (newState: T) => void] {
  let currentState = state
  const changeState = (newState: T) => {
    currentState = newState
  }

  return [currentState, changeState]
}

//const counter: number
//const setState: (newState: number) => void
const [counter, setState] = useState(10)
// 10
console.log(counter);

type、interface

type

type起别名,常用于非对象类型

  • 修饰符 可选? 只读readonly
// 非对象类型
type idType = number | string
let id1:idType = 1
let id2:idType = '1'

// 对象类型
type pointType = {x:number,y:number,z?:number}
let point:pointType = {1,2,3}

interface

接口性质

interface 只能声明对象类型

  • 可以多次声明同一个接口名称
  • 可以继承
  • 修饰符 可选? 只读readonly

多次声明同一个接口名称:

interface pointType {
  x: number,
  y: number
}

interface pointType {
  z?: number
}

const p1: pointType = {
  x: 1,
  y: 2,
}

const p2: pointType = {
  x: 1,
  y: 2,
  z: 3
}

//{ x: 1, y: 2 } object
console.log(p1, typeof p1);
//{ x: 1, y: 2, z: 3 } object
console.log(p2, typeof p2);

接口继承:能多继承

interface IPerson {
  name: string,
  age: number
}

interface IAnimal {
  sleep?: string,
}

interface IStu extends IPerson,IAnimal {
  sno: number | string
}

const s1: IStu = {
  name: 'ccc',
  age: 999,
  sno: 1
}

对象接口

// 定义对象接口
interface Person {
  // 1.只读属性
  readonly id: number,
  name: string,
  age: number,
  // 2.可选属性
  gender?: string,
  // 3.动态属性名
  [attrName: string]: any
}

let p1: Person = {
  id: 1,
  name: 'cjc',
  age: 999,
  song: 'jinitaimei'
}

类接口

interface person {
  age: number,
  eat(food: string): string
}

// 类实现接口
// 能同时实现多个接口
class stu implements person {
  age: number
  eat(food: string): string
  eat(food: string) {
    return 'apple'
  }
}

函数接口

// 函数接口
interface Ifun{
  // (形参名1:类型1,形参名2:类型2):返回值类型
  (a:string,b:string):boolean
}

const func1:Ifun = function(a:string,b:string):boolean{
  return a.search(b) !== -1
}

索引签名

数组(可索引类型)

// 数组的接口
interface IArray{
  // 属性名为number类型(即数组下标为number)
  // 属性值为任意类型any
  [index:number]:any
}

let arr5:IArray = [1,2,'a',true]

联合类型、交叉类型

联合类型

const a:number|string|boolean = true

交叉类型

interface IPerson {
  name: string,
  age: number
}

interface IStu extends IPerson {
  name: string
  study: () => void
}

// 交叉类型 &
type StuType = IPerson & IStu

const s1: StuType = {
  name: 'ccc',
  age: 999,
  study() {
    console.log(1);
  }
}

类型断言、非空类型断言

当TS没法获取某个确定类型时,使用类型断言(Type Assertions)

// let div: HTMLDivElement | null
let div = document.querySelector('div')

// 当用类获取元素时,TS无法推断是什么类型
// let box1: Element | null
let box1 = document.querySelector('.box')

// let box2: HTMLDivElement
let box2 = document.querySelector('.box') as HTMLDivElement

断言能断言成更具体的类型或不太具体的类型

// const age: number
const age: number = 99
// const age2: any
const age2 = age as any
// const age3: string
const age3 = age2 as string

非空断言


interface IPerson {
  name: string,
  age: number,
  hobbies?: string[]
}

const p1: IPerson = {
  name: 'ccc',
  age: 999,
  hobbies: ['a']
}

// 访问属性 可选连 ?
console.log('设置之后:', p1.hobbies?.[0]);

// 设置属性
// 方式1 类型缩小
if (p1.hobbies) {
  p1.hobbies[0] = 'rap'
}

// 方式2 非空类型断言
p1.hobbies![0] = 'rap'

console.log('设置之后:', p1.hobbies?.[0]);

字面量类型

function request(url: string, method: "get" | "post") { }

const info1 = {
  url: 'xxx',
  method: "get"
}
// info1中method的类型为string
// 方式1 断言为get
request(info1.url, info1.method as "get")


// 方式2 将info对象类型断言为字面量类型  
// 字面量推理
// const info2: { url: string, method: "get" | "post" } = {
//   url: "xxx",
//   method: "get"
// }
const info2 = {
  url: "xxx",
  method: "get"
} as const

request(info2.url, info2.method)

类型缩小

  • typeof
  • ===!== == != 常用于字面量类型的判断
  • instanceof
  • in

TS面向对象

构造函数语法糖

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

// 以上代码的语法糖形式:
class Person2 {
  constructor(public name: string, public age: number) { }
}

修饰符

成员修饰符

  • public 公有成员任何地方可见,默认值
  • private 私有成员,在同一个类中可见
  • protected 在类及子类中可见

属性修饰符

  • readonly 只读属性

setter/getter

class Person {

  // 约定俗成,私有属性 _表示
  constructor(private _name: string) {}

  set name(newVal: string) {
    console.log('设置私有属性_name:');
    this._name = newVal
  }

  get name() {
    console.log('获取私有属性_name:');
    return this._name
  } 
}

let p1 = new Person('ccc')
console.log(p1.name);
p1.name = 'CJC'
console.log(p1.name);

//打印结果: 
//获取私有属性_name:
//ccc
//设置私有属性_name:
//获取私有属性_name:
//CJC

抽象类

索引签名

interface ICollection {
  [index: number]: any
  length: number
}

function printCollection(collection: ICollection) {
  for (let i = 0; i < collection.length; i++) {
    console.log(collection[i]);
  }
}

const arr = [1, 2, 3]
printCollection(arr)

const str = 'abc'
printCollection(str)

枚举类型

enum nums {
  one = 1,
  two,
  three
}

// 从1开始递增
// 3
console.log(nums.three);
// 通过名称拿到值
// 也能从值拿到名称
// { '1': 'one', '2': 'two', '3': 'three', one: 1, two: 2, three: 3 }
console.log(nums);

泛型

基本使用

function foo<T, E>(a: T, b: E) { }

// 1.自动类型推断
foo(1, { name: 'ccc', age: 999 })

// 2. 类型注解
foo<number, { name: string, age: number }>(1, { name: 'ccc', age: 999 })

泛型约束

例:传入的类型必须有length属性

interface ILength {
  length: number
}

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

console.log('arr:', getLength([1, 2, 3]));
console.log('str:', getLength("abc"));

例:根据对象的键(不管是否存在),获取对象的值

// function getProperty(obj: any, key: any): any
function getProperty(obj, key) {
  return obj[key]
}

const p = {
  name: 'ccc',
  age: 99
}

// ccc
console.log(getProperty(p, "name"));

// 若没有类型约束,可以传入p中不存在的键
// undefined
console.log(getProperty(p, "gender"));

例:根据对象的键(只能获取对象p中存在的键),获取对象的值
keyof 获取p中所有的键组成的联合类型,如string|nunmber

// function getProperty(obj: O, key: K): O[K]
function getProperty<O, K extends keyof O>(obj: O, key: K) {
  return obj[key]
}

const p = {
  name: 'ccc',
  age: 99
}

// ccc
console.log(getProperty(p, "name"));

// 类型“"gender"”的参数不能赋给类型“"name" | "age"”的参数
// console.log(getProperty(p, "gender"));

映射类型

  1. 拷贝传入类型T的所有键值对到另一个类型
  2. 使用type定义映射类型,不能使用interface定义
  3. 拷贝过程中能对类型进行操作
interface IPerson {
  name: string
  age: number
}

type MapType<T> = {
  // 拷贝传入类型T的所有键值对
  [key in keyof T]: T[key]
}

type NewPerson = MapType<IPerson>

let p1: NewPerson = { name: 'ccc', age: 999 }

例子:将所有类型转为必填

  • 在修饰符之前可以加上减号-,表示去除该修饰符
  • 在修饰符之前可以加上加号+,默认省略
interface IPerson {
  name: string
  age?: number
  readonly gender: string
}

type mapType<T> = {
  // 拷贝传入类型T的所有键值对
  // - 去除修饰符
  -readonly [key in keyof T]-?: T[key]
}

type NewPerson = mapType<IPerson>

let p1: NewPerson = { name: 'ccc', age: 999, gender: 'male' }

ts模块化

没有export的js或ts文件会被认为是脚本。脚本中声明的变量和类型等在全局作用域中。

将脚本变为模块 export {} (即使没有导出任何内容)

导出类型
TypeScript基础_第3张图片
导入类型
在这里插入图片描述
在这里插入图片描述

ts类型管理与查找规则

xxx.d.ts称为类型声明文件(Type Declaration)或类型定义文件(Type Definition)

ts内置类型声明文件

TypeScript基础_第4张图片

第三方库类型声明文件

  1. axios等第三方库包含自己编写的 xx.d.ts类型声明文件
  2. react等不含有类型声明文件,则需要另外导入类型声明库
npm i react
npm i -S @types/react

TypeScript基础_第5张图片

自定义类型声明文件

自定义类型声明文件 xxx.d.ts

// 声明变量类型
declare const name:string
declare const age:number

// 声明函数类型
declare function foo(a:number):number

// 声明类的类型
declare class Person {
	constructor(public name:string,public age:number)
}

// 声明模块
// 假设lodash没有类型库
declare module "lodash" {
	export function join(args: any[]):string;
}

// 声明命名空间
// jQuery等使用CDN方式使用时(不是引入模块的方式)
declare namespace $ {
	export function ajax(setting:any):any
}

例:ts中导入图片文件,报错。需要声明文件模块
TypeScript基础_第6张图片
在类型声明文件中:

declare module "*.avif"

tsconfig.json

  1. tsconfig.json文件所在目录即为TS项目的根目录
  2. 指定该根目录下的ts文件编译方式
  3. webpack中使用ts-loader打包时,自动读取tsconfig配置文件来编译ts代码
    TypeScript基础_第7张图片

TypeScript基础_第8张图片

你可能感兴趣的:(TypeScript,typescript,webpack,前端)