半天入门 TypeScript (上)

287 阅读8分钟

我的总结

graph TD
Start --> Stop

1.TypeScript 是什么

TypeScript 是微软开发的开源编程语言。2012年10月,微软发布了首个公开版本的TypeScript,2013年6月19日,在经历了一个预览版之后微软正式发布了正式版TypeScript,可以在任何运行 JavaScript 的地方运行。TypeScript 起源于使用JavaScript开发的大型项目 。由于JavaScript语言本身的局限性,难以胜任和维护大型项目开发。因此微软开发了TypeScript ,使得其能够胜任开发大型项目。


2.TypeScript和JS的对比

一下总结共四点

  • 动态和静态编程语言

    js属于动态类型的编程语言,TS属于静态类型的编程语言

    js:边解释边执行,错误只能在运行阶段才能发现。 ts: 它要先编译,再执行(不能直接执行,需要编译成js才能执行)

  • ts完全兼容javascript,它可以编译成javascript

image.png

  • ts有类型支持,有强大的代码类型提示

    在写代码的过程中就能发现问题

  • 前端生态

    前端三大框架: Vue 3 源码使用 TS 重写、Angular 默认支持 TS、React 与 TS 完美配合,TypeScript 已成为大中型前端 项目的首选编程语言。

    目前,前端最新的开发技术栈:

    1. React: TS + Hooks
    2. Vue: TS + Vue3

3.TypeScript初体验

首先下包  npm i -g typescript
验证是否安装成功并查看版本号  tsc –v
注意:Mac 电脑安装全局包时,需要添加 `sudo` 获取权限:`sudo npm i -g typescript`
   创建ts文件。例如 hello.ts 文件(注意:TS 文件的后缀名为.ts)
   编译。将 TS 编译为 JS 输入       tsc hello.ts     此时,在同级目录中会出现一个同名的 JS 文件
    在node中运行。在终端中输入命令     node hello.js

4.ts-node 简化运行 TS 的步骤

简化方式

使用 ts-node 包,直接在 Node.js 中执行 TS 代码。它提供了 ts-node 命令,可以简化执行命令。

   装包     npm i -g ts-node
   使用方式:     ts-node hello.ts

ts-node 命令在内部偷偷的将 TS -> JS,然后,再运行 JS 代码

5.运行ts代码报错问题

如遇到以下错误

Cannot find name 'console'. Do you need to change your target library? Try changing the lib compiler option to include 'dom'

tsc --init 命名,在根目录下生成配置文件 tsconfig.json

变量冲突

1.写代码时,用{ }整体给包起来
2.export{ }包裹


6.TS类型注解

什么是类型注解?

可以显示标记出代码中的意外行为,从而降低了发生错误的可能性

变量名: 类型 = 初始值

栗子 
let  name:string = 'jack'
let  age:number  =  18      (:number 就是类型注解)

注意 :  如果 let age: number = '18'  会直接报错

7.TS的类型

JS 已有类型

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

TS 新增类型

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

8.原始类型

number/string/boolean/null/undefined/symbol

// 数值类型
let age: number = 18

// 字符串类型
let myName: string = '小花'

// 布尔类型
let isLoading: boolean = false

// undefined
let un: undefined = undefined

// null
let timer:null = null

// symbol
let uniKey:symbol = Symbol()

9.类型推论

什么是类型推论?

在 TS 中,某些没有明确指定类型的情况下,TS 的类型推论机制会自动提供类型。好处:由于类型推论的存在,有些情况下的类型注解可以省略不写。

// 变量 age 的类型被自动推断为:number
let age = 18


// 函数返回值的类型被自动推断为:number
function add(num1: number, num2: number) {
  return num1 + num2
}

一个实用的小技巧将鼠标放在所属方法或者对象上通过VsCode提示可以知道要传入的类型有哪些哦 : 例如下面这个图,提示你传的是dom节点

image.png


10.联合类型

什么是联合类型?

在Ts中以 | 链接,即有两个或者两个以上的其他类型组合成的类型叫做联合类型,可以表示可以是这些类型的任意一种类型

| 在vue中的过滤器也有这个用法 点击 查看过滤器如何使用

如 let 变量: 类型1 | 类型2 | 类型3 .... = 初始值

let arr: (number | string)[] = [1, 'a', 3, 'b']


let var1: string | number = 1
var1 = '1'

//定义一个定时器
let timeID:number|null =null
timeID=setTimeout(()=>{},1000)

冷知识 注意定时器返回的是number类型数据


11.类型别名

什么是类别别名?

顾名思义就是给类别叫一个别的名字

用法:

type 自己定义的名字 = 类型

type s = string // 定义

const str1:s = 'abc'
const str2:string = 'abc'

type 自己定义的名字= 类型 | 类型

 type NewType = string | number

 let a: NewType = 1
 let b: NewType = '1'

12.数组类型

数组类型两种用法

let 变量: 类型[] = [值1,...]

let 变量: Array<类型> = [值1,...]

推荐写法一 简单

// 写法一:
let numbers: number[] = [1, 3, 5] //  numbers必须是数组,每个元素都必须是数字

// 写法二:
let strings: Array<string> = ['a', 'b', 'c'] //  strings必须是数组,每个元素都必须是字符串

13.函数-单个定义

普通函数 function 函数名( 类型=默认值,类型=默认值,...): 返回值类型 { }

箭头函数 const 函数名(类型=默认值,类型=默认值, ...):返回值类型 => { }

// 声明式
function add(num1: number, num2: number): number {
  return num1 + num2
}

// 箭头函数
const add = (num1: number, num2: number): number => {
  return num1 + num2
}

add(1,'1') // 报错

14.函数-统一定义函数格式

如 13上述 重复的代码可以使用更简洁的方法

将多个相同的代码定义为自定义类型

type Fn = (n1:number,n2:number) => number  //定义一个自定义类型

const add1 : Fn = (a,b)=>{return a+b }
const add2 : Fn = (a,b)=>{return a-b }

15.函数-返回值类型void

在Ts中,如果函数没有返回值,使用void类型管理

有三种情况可以使用

  • 不写return
  • 写return ,但是后面不接内容
  • 写return undefined
// 如果什么都不写,此时,add 函数的返回值类型为: void
const add = () => {
 console.log('Hello')
}

// 如果return之后什么都不写,此时,add 函数的返回值类型为: void
const add = () => { 
return
}

const add = (): void => {
  // 此处,返回的 undefined 是 JS 中的一个值
  return undefined
}
// 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同
const add = (): void => {}

16.函数-可选参数

可选参数可传可不传

用法:function fn(count1?:number,count2?number):void{}

fn(1)

注意可选参数不能与默认参数一起使用

function mySlice(start?: number=0, end?: number=11): void {} 报错!!!


17.对象类型-单独使用

可配合可选参数使用===>
const 对象名: {
  属性名1:类型1,
  属性名2:类型2,
  方法名1(形参1: 类型1,形参2: 类型2): 返回值类型,
  方法名2:(形参1: 类型1,形参2: 类型2) => 返回值类型
} = { 属性名1: 值1,属性名2:值2  }

const fn:{
    name: string,
    price: number,
    func: ()=>string,
    age?:number
}  = {
    name: '手机', 
    price: 2000, 
    func:function(){ return '打电话' }
}

18.对象类型-类型别名

type obj={
    name:string,
    age:number
    sayHi():void
}

let Fn:obj={
    name:'jack',
    age:18,
    sayHi(){
        console.log('Hello')
    }
}

19.接口

用法: interface 接口名 {属性1: 类型, 属性2: 类型,}

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

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

  • 不同点:

    • 接口,只能为对象指定类型。它可以继承。
    • 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名
interface IGoodItem  {
   name: string,
   price: number,
   func: ()=>string
}

const good1: IGoodItem = {
   name: '手表',
   price: 200,
   func: function() {
       return '看时间'
   }
}
const good2: IGoodItem = {
    name: '手机',
    price: 2000,
    func: function() {
        return '打电话'
    }
}

20.接口继承

如果遇到一下情景,可以使用继承,将公共的属性抽离出来,再定义

interface IPoint2D { x: number; y: number }
interface IPoint3D { x: number; y: number; z: number }
写法
interface 接口2 extends 接口1 {
    属性1: 类型1// 接口2中特有的类型
    ... 
}
运用
interface Point2D { x: number; y: number }
// 继承 Point2D
interface Point3D extends Point2D {
  z: number
}

这样Point3D就继承了Point2D的两个属性,再定义一个z属性

21.元组

什么是元组?

固定数组只能有几个值,且定义类型

元组是一种特殊的数组。有两点特殊之处:

  1. 它约定了的元素个数
  2. 它约定了特定索引对应的数据类型

用法

//例如经纬度只能有两个数字
let position: [number, number] = [39.5427, 116.2317]
//模拟定义useState
function useState(num:number):[number,(number)=>{void}]{
    setUpdataNum(newnum)=>{
        num=newnum
    }
    return [num, setUpdataNum]
}
const [num,setnum]=useState(10)

22.字面量类型

任意字面量都可以作为类型使用,如let a: 'abc' = 'abc'

type Gender = 'girl' | 'boy'
let g1: Gender = 'girl' // 正确
let g2: Gender = 'boy' // 正确
let g3: Gender = 'man' // 错误

优势:相比于 string 类型,使用字面量类型更加精确、严谨