TypeScript:基础

111 阅读6分钟

启用TS

将TS编译成JS的方法

  1. 通用方法:webpack + babel

  2. 新的方法:Vite2(有默认配置)

参考文档

运行create-vite-app ts-vite-demo-1 --template react-ts 创建了react-ts类型的文件,文件名为ts-vite-demo-1,然后yarn ,再运行yarn dev

image.png

ts和tsx的区别:tsx = ts + jsxts = tswebpack + ts = ts + jsx

  1. 手动使用:tsc(TypeScript compiler)

终端运行tsc 1.ts,将 ts文件 编译为 js文件,然后再运行node 1.js

类型 V.S. 类

ts语法:

var x:string = 'hi' //string是类型的一种

JS的基本类型:

  • 简单类型:null,undefined,string,number,bool,bigint

  • 复杂类型:object

这里的类型是指数据的类型(type),在JS里面有一个关键词是typeof,是用来获取一个东西的类型

typeof有两个著名的bug:1、如果typeof后面接的是函数,那么返回的就是function;2、如果typeof后面接的是null,那么返回的就是object

JS 中的类

JS中的类只研究基本类型中的object,这个类是人为发明的,面向对象编程

面向对象编程:1、基于class关键字的面向对象编程;2、基于原型的面向对象编程

  • 基于class:
class Person = {
  属性1
  属性2
  属性3
  方法1
  方法2
  方法3
}

const p1 = new Person()
const p2 = new Person()
  • 基于原型
function Person() {
  var temp = {}
  temp.属性1
  temp.属性2
  temp.属性3
  temp.方法1
  temp.方法2
  temp.方法3
  temp.__proyo__ = 共有属性
  return temp
} 
const p1 = Person()
p1.属性1
p1.方法1()

类型和类的区别: 类型的英文是type,类型是对所有数据的分组(数据的天然分类);类的英文是class,类是对象的抽象编程(等价于class关键字,类就是对对象的人为的一种设计方法(就是创造一个对象,需要先声明一个类,用类new出一个对象))

类型的两个好处

  1. 减少bug

不用运行就知道运行时的bug

  1. 提示

随时随地进行类型的匹配

TS支持的JS类型

const a:undefined = undefined
const b:null = null
const c:string = 'hi'
const d:boolean = true
const e:symbol = Symbol('hi')
const f:bigint = 123n
const g:number = 123
//前面这样写,除了object

const obj:Object = {} //类
const obj0:object = [] //类型
//两者没有明显区别,但是一般情况下将类型具体化
const arr:Array<string|number|null> = [] //告诉arr,里面的内容是string或number或null

//函数写法
//const add = (a,b) => a+b
const add1 = (a:number,b:number):number => a+b //接受a是number,b是number,返回值也是number(返回值在箭头的前面写)
const add2: (a:number, b:number)=> number = (a, b) => a + b 
type Add = (a:number, b:number)=> number
const add3:Add = (a, b) => a + b
//以上3中写法都可以,但是一般用第三种写法

//如果想要描述一个函数接受一个a和b,返回一个和,同时它自身有一个属性

interface AddWithProps{
  (a: number, b: number) : number
  xxx: string 
} //意思是它是一个函数,它的第一个参数是a,第二个参数是b,返回的值是number
// 声明一个函数,它有xxx属性

const add4:AddWithProps = (a, b) => a + b
add4.xxx = 'yyy'


//1. 类型写在函数体(具体参考 add1)
//2. :后面(具体参考add2)
//3. type 缩写(具体参考add3)
//4. 有属性,只能用 interface(具体参考add4)

export{}

TS中的any、unknown、void、never、enum、tuple

参考文档

any

let a: any = 'hi' 

any没有任何限制

unknown

let b: unknown = JSON.parse('{"name":"lily"}') 

unknown要用的话,必须明确它是什么东西

  • anyunknown的区别:unknown不是手写出来的值,而是从外界获取到的值。any是永远不知道是什么类型,可以是任何类型;而unknown是现在不知道但是用的时候必须明确知道是什么类型

void

let print: () => void = function(){console.log(1)}
print()

void就是不要函数的返回值

never

如果代码中让一个东西变成了never,说明代码出错了

type Dir = 1 | 2 | 3 | 4 | undefined 
let dir: Dir
switch (dir){
  case 1:
    break;
  case 2:
    break;
  case 3:
    break;
  case 4:
    break;
  case undefined:
    break;
  default:
    console.log(dir)
    break
}

never表示空集,什么都没有,既不是undefined也不是null,表示不应该存在的,没有这个类型,例如:

type X = number & string 
//等价于type X = never

tuple

元组

let p: [number, number] = [100,200]
let p1: [number, string] = [100, 'x']
let p2: [number, string, boolean] = [100, 'x', true]

意思为p是一个元组,元组就是不可变更长度的数组,如果想要固定一个数组的长度就是元组,然后把每一个元素的类型写上 元组只是TS里面的概念,JS里面不存在元组

enum

枚举

enum Dir2 {东,南,西,北}
let d: Dir2 = Dir2.东
let d2: Dir2 = Dir2.西
console.log(d)

type Dir3 = '东'|'男'|'西'|'北'
let dir2: Dir3 = '东'
let dir3: Dir3 = '西' //建议使用这种写法

枚举就是把数字0,1,2,3,4变成一个对应的标志,是标志而不是字符串,只有TS认识这个标志,JS不存在这个标志。

总结

  • JS和TS都有的类型:nullundefinednumberstringBooleansymbolbigintobjectclassName type interface

  • TS 独有的类型:anyunknownneverenum(枚举)tuple(元组)

给不同数据加type

const fn: (a: number) => number =
  function (x){return x + 1}
const a: Array<number> = [1,2,3] //可以理解为Array是个函数,它接受一个参数;调用Array这个函数,它接受number
  • 第一种语法是冒号后面加个类型

  • 第二种语法就是类型后面加个尖括号,就是传参,叫做泛型泛型就是给这个类型传个参数

如果要描述一个对象的类型的时候,不要再用object,而是用它对应的class,如果是数组,它的class就是Array,如果是函数,它在TS中"Function"不是泛型类型,要写成箭头函数的形式。

class是类型还是值?

既是值又是类型

// var x:类型 = 值
class A {

}
const B = A // JS 
const a:A = new A() // TS 声明一个A的实例,那么等号前面的A是类型,等号后面的A是值

export {}

对于JS来说,A就是一个值;对于TS来说,它是类型,那么A的类型是object

联合类型与区分联合类型

联合类型(|) and 交叉类型(&)

联合类型

  • 联合类型
const f = (n: string | number)=>{}
  • 类型推测
type A = {
  name: string;
  age: number
}
type B = {
  name: string;
  gender: String;
}
const f = (n: number | B) => {
  if(typeof n=== 'number') {
    n.toFixed()  //TS预测这里的n是number
  }else{
    n.name  //TS预测这里的n是B
  } //这个时候可以toFixed,是因为TS会做类型收展,通过代码会预测n的类型
}

export {}

TS在写代码的过程中就能猜到n的类型,在一个分支是多少,在另一个分支是多少

  • 区分联合类型
type A = {
  name: 'a';
  age: number
}
type B = {
  name: 'b';
  gender: String;
}
const f = (n: A | B) => {
  if(n.name === 'a'){ 
    n.age // n是A类型
  }else{
    n.gender // n是B类型
  }
}

export {}

需要这两个类型必须有一个相同的key,这个key叫什么无所谓,只要是相同的就好

必须用if...else做出两个分支选择,只要做出一个分支选择,那么TS就会知道n的类型

交叉类型

交叉类型&不能用于简单类型,简单类型就是除了object以外的7种类型。简单类型之间是没有交叉的

type A = {name:string} & {age:number}

const a:A = {
  name: 'lily',
  age: 18
}

&一般用于连接两个复杂类型

如果叠加一个类型,会成never,如果A成never了,后面不管是什么都会报错

image.png