typescript 的出现是为 javascript 添加类型约束

  • 编写的 ts 代码最终都会编译成 js 代码运行,浏览器不支持直接运行 ts 类型的代码

变量的声明

var/let/const 变量名:数据类型 = 赋值

例如: const hello: string= 'hello world'

数据类型的类别

number

let num1: number = 6;
let num2: number = 0xf00d;
let num3: number = 0b1010;
let num4: number = 0o744;

支持二、八、十六进制

不区分 int 整数 和 double 浮点数

boolean

取值 ture & false

let isShow: boolean = false;

string

const name: string = 'fantasy'
// 同样也支持模板字符串
const age: number = 18
const info = `name is ${name},age is ${age}`

Array

// 约束数组内容是 string 类型
const arr1 string[] = ['aaa','bbb','ccc']
// 泛型
const arr2 Array<string> = ['ddd','eee','fff']

object

object 可以表述一个对象

const infos: object = {
  name: 'fantasy',
  age: 18
}

// 输出 fantasy
console.log(infos.name)

// 不能赋值 error
infos.age=20

symbol

// symbol来定义相同的名称,Symbol函数返回的是不同的值
const s1: symbol = Symbol("title")
const s2: symbol = Symbol("title")

cosnt person = {
  [s1]: '医生',
  [s2]: '护士'
}

null & undefined

undefined和null两者各自有自己的类型分别叫做undefined和null

它们的本身的类型用处不是很大

let u: undefined = undefined;
let n: null = null;

any

无法确定一个变量的类型,并且可能它会发生变化,可以使用any类型

let id: any = 123
// 可以赋值任意类型 相当于回到JS
id = '123'
id = ['123']
id = {name: fantasy}

void

某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,返回值类型为 void

function hello(): void {
  console.log('hello world')
}

声明一个void类型的变量没有什么用,只能为它赋予undefined和null

never

never类型表示的是那些永不存在的值的类型。

例如,函数一个死循环和抛出一个异常

function loop(): never{
  while(true){
    console.log('hello')      
  }
}

function errorFn(): never{
  throw new Error()
}

Tuple

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

let arr: [string,number] = ['name',18]
// string 可以运行
console.log(arr[0].substr(1))

// number 报错 error
console.log(arr[1].substr(1))

// 可以越界,类型为上面其中一种
arr[2] = 'hello'

函数的类型

参数

声明函数时,在每个参数后添加类型注解,以声明函数接受的参数类型

function foo(name: string,age: number){
  console.log(name,age)
}

返回值

注解出现在函数列表的后面

function(num1: number,num2: number): number{
  return num1+num2
}

匿名函数

当函数出现在TypeScript可以确定该函数会被如何调用的地方时,参数会自动指定类型

const lists = ['aaa','bbb','ccc']

lists.forEach(item=>{
  console.log(item.toUpperCase())
})

上下文类型(contextual typing)可以帮助确定参数和返回值的类型
即TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型

变量的类型推导

开发中并不会在声明每一个变量时都写上对应的数据类型
TypeScript本身的可以特性帮助我们推断出对应的变量类型

let str = 'hello'
// 报错 error
// 变量第一次赋值时,根据赋值内容的类型,推断类型
str = 123

联合类型

  • 联合类型表示由多个类型组成
  • 表示可以是多个类型中任意一个类型
  • 类型中每一个类型被称为联合成员
function foo(id: number|string ){
  // 如需要根据类型使用
  // 进行类型缩小
  if(typeof id === string){
    console.log(id.toUpperCase())
  }else
    console.log(id)
}

foo("abc")
foo(123)

type类型别名

为了类型注解可以方便多次使用可以类型别名

type infosType = {
  name: string
  age: number
}

function foo(infos: infosType){
  console.log('名字',infos.name,'年龄',infos.age)
  
}

foo({name: 'jay' ,age: 18})

interface接口

接口用来声明对象类型,与type别名大致相同

interface Iinfos {
  name: string,
  age: number
}

function foo(infos: Iinfos){
  console.log('名字',infos.name,'年龄',infos.age)
}

type & interface 区别

  • 如果是定义非对象类型,通常推荐使用type
  • interface可以重复定义某一个的接口的属性和方法
  • type定义的是别名,别名是不能重复
interface Iinfo {
  name: string
  run: ()=>void
}
// 重复定义 这是运行的
// 如用type声明会error
interface Iinfo {
  age: number
}

交叉类型

交叉类型表示同时满足多个条件

通常应用于对象类型交叉

interface Iinfo {
  name: string
  age: number
}
interface IRun {
  run: ()=>void
}

const person: Iinfo&IRun = {
  name:'jay',
  age: 18,
  run: function(){
    console.log('running')
  }
}

类型断言

某种情况TypeScript无法获取具体的类型信息,需要使用类型断言

as : 类型

const myimg = document.getElementById('pic') as HTMLImageElement

myimg.src='/图片地址'

非空断言

非空断言使用的是 ! ,表示可以确定某个标识符是有值的,跳过ts在编译阶段对它的检测

function foo(msg?: string){
  // error 值可能是undefined
  console.log(msg.toUpperCase())
  // 如确保有类型 使用非空短言
  console.log(msg!.toUpperCase())
}

字面量类型

如:

  let msg: 'hello' ='hello'
  // 报错,你好 类型不是 hello
  msg='你好'

用 const 声明的常量默认是字面量类型
默认情况这样作意义不大
搭配联合类型使用

type positionType = 'left' | 'right' | 'up' | 'down'

function changePosition(position: positionType){
  console.log('修改反向:',position)
}

changePosition('left')

字面量推理

const info ={
  url: "https://127.0.0.1"
  method: "GET"
  
}

function Myrequest(url: string, method: 'GET'|'POST'){
  console.log(url,method)
}
// 调用会报错,inof.method不是字面量类型
// 因为字面量推理会得出 info其实是一个 {url: string, method: string}
Myrequest(info.url,info.method)

// 解决方法 使用类型断言
// 方法一 调用时使用
Myrequest(info.url,info.method as 'GET')

// 方法二 对象上使用
const info ={
  url: "https://127.0.0.1"
  method: "GET"
  
} as const

类型缩小

  • 通过类似于 typeof padding === "number" 的判断语句,来改变TypeScript的执行路径
  • 给定的执行路径中,我们可以缩小比声明时更小的类型,这个过程称之为 缩小( Narrowing )
  • 我们编写的 typeof padding === "number 可以称之为 类型保护(type guards)

常见的类型保护:typeof===,!==instanceofin

// typeof
type idType = string | number

function foo(id: idType){
  if(id typeof string){
    console.log("string:",id)
  }else
  {
    console.log("number:",id)
  }

}

// === !==

type positionType = 'left' | 'right'

function changePosition(position: positionType){
  if(position==='left'){
    console.log('change left')
  }else {
    console.log('change right')
  }
}

// instanceof 检查一个值是不是另一个值的实例

function outputDate(date: Date|string){
  // 判断date算不算 Date 的实例
  if(data instanceof Date){
    console.log(date.toLocaleString())
  } else{
    console.log(date)
  }
  
}

// in 指定的属性在指定的对象或其原型链中,则in 运算符返回true
type fish = {swim:()=>void}
type kun = {rap:()=>void}
function move(animal: fish|kun){
  if('swim' in animal){
    console.log('swimming')
  }else{
    console.log('唱 跳 rap')
  }
}


参考资料

TS中文网

coderwhy前端课程