TypeScript学习1

149 阅读7分钟

代码示例传送门

类型检测问题

代码对比

  • JavaScript
// foo没有进行参数检测
// 1. 参数类型检测
// 2. 传入参数内容检测
function foo(message) {
  console.log(message.length);
}
​
foo("Hello JavaScript")
​
// 不传参数,undefined的length不存在
// 只能在执行的时候报错误
foo()
​
// foo()后续代码无法执行
console.log("Is here!");
  • Typescript
let info: string = "hha"
// 不同类型不能赋值
// info = 123 // 默认所有ts文件都是同一个作用域,命名重复会报错
function fn(message: string) {
  console.log(message.length);
}
​
// 未传参数报错
fn()  // 代码未执行就报错提示

image-20220210171701630.png

一目了然JavaScript和Typescript之间的区别,变量的类型检测

变量定义

变量定义的格式

ts变量定义格式 var/let/const 变量名: 类型注解 = 值

值 是一个表达式也没关系,只要能够拥有类型

var name: string = "coder"
let age: number = 18
const height: number = 1.90// string: TypeScript中字符串类型
// String:JavaScript中的字符串包装类的类型
// 大小写注意区分
const message: string = "Hello TypeScript"// foo没有添加类型注解
// 赋值时默认会将值的类型给变量定义类型 ————类型推导(inter)
// 所以 foo 的类型是 string
let foo = "foo"

注意: ts文件共用一个作用域,因此命名可能重复; 可通过模块化的方式,拥有自己的作用域

解决方案:在文件最后一行加上该代码

export {}

number

let num: number = 123
// num = "123"let num1: number = 100
let num2: number = 0b111 // 二进制
let num3: number = 0o456 // 八进制
let num4: number = 0x123F // 十六进制console.log(num1, num2, num3, num4);

boolean

let flag: boolean = true
flag = false
flag = 20 > 30

string

let message: string = "hello"
// 默认情况下,能够推导出类型可不写
let word = "typescript"
​
​
// 参数中无法推导,则需要确定参数类型
function foo(message: string, word: string) {
  let newMes = `${message} ${word}`console.log(newMes);
}

array

// 确定:names是一个数组类型
// 同一个数组类型中的数据最好是固定类型的
// 数组中存放不同类型数据是不好的习惯
const names: Array<string> = [] // 不推荐(jsx中存在冲突)
const namesArr: string[] = [] // 推荐// 会报错,因为限定了数组中的类型
// names.push(123)
​
names.push("tom")
namesArr.push("jack")

object

// 存在弊端:无法取出info的属性
// const info: object = {
//   name: "tom",
//   age: 18
// }// 推荐写法
const info = {
  name: "jack",
  age: 18
}

null 和 undefined

// null类型只有一个值————null
const n1: null = null// 默认是 any类型
let n2 = null
n2 = "string"// undefined只有一个值——undefined
let u1: undefined = undefined

Symbol

const title1 = Symbol("title")
const title2 = Symbol("title") 
​
const info = {
  title: "hello symbol",
  [title1]: "hello",
  [title2]: "typescript"
}

TypeScript数据类型

下面介绍的是typescript自带的数据类型

any类型

讨巧类型,不想限定JavaScript变量添加具体的数据类型(js原生一样)

// 进行一些类型断言  as any
let message: any = "hello world"// 类型注入为any,message可以是任何类型
message = 123
message = "hello typescript"
message = () => {}

unknown类型

当类型不确定的时候,避免变量被滥用,可以使用unknown类型,不推荐使用any类型。

与any类型的区别:

  1. unknown类型只能赋值给 any 和 unknown 类型
  2. any类型可以赋值给任意类型
function foo() {
  return "abc"
}
​
function bar() {
  return 123
}
​
let flag = true
let result: unknown
if (flag) {
  result = foo()
} else {
  result = bar()
}
// result是unknown类型时,赋值给其他类型会报错
// let info: string = resultconsole.log(result);

void类型

函数返回值的默认类型

// 当函数没有返回值的时候,默认会加上void类型。可不写
function sum(num1:number, num2: number): void {
  console.log(num1 + num2);
}
​
sum(20, 30)

never类型

函数注入类型 never:表示永远不会有返回值

function foo(): never {
  // 死循环
  while (true) {
​
  }
}

应用场景

//  | :是联合类型,代表 既。。 也可。。。
// 当message只是string和number类型时的函数,突然想要添加验证boolean类型的验证时
// 在参数中添加 boolean并不够,default中会报错,never表示永远不会
// 因此需要添加一个case 验证boolean类型才能通过
// 这样函数减少了出错的机会
function handleMessage(message: string | number | boolean) {
  switch (typeof message) {
    case 'string': console.log("string"); break;
    case "number": console.log("string"); break;
    case "boolean": console.log("boolean");break;
    default:
      const check: never = message
  }
}

tuple元组

tuple元组:多种元素的组合

// any
const info: any[] = ["tom", 18 , true]
​
// 拿到any数组的元素,类型推导默认为any类型
// newName类型是 any
const newName = info[0]
console.log(newName.length)
​
// 元组类型,指定数组中的各元素的类型
const infoArr:[string, number, boolean] = ["why", 18 , true]
​
// myName类型是 string
const myName = infoArr[0]
console.log(myName);

应用场景

// 泛型 T: 类型推导
function useState<T>(state: T) {
  let currentState = state
​
  const changeState = (newState: T) => {
    currentState = newState
  }
​
  // any 数组
  // const arr: any[] = [currentState, changeState]
  // return arrconst tuple: [T, (newState: T) => void] = [currentState, changeState]
  return tuple
}
​
// 使用 any数组的话,每一项都是any,情况不太友好
// 使用元组的话,每项的类型都能够被限定
// (将any替换成 T)使用泛型,能够间接的进行类型推导,更能明确变量的类型
const [counter, setCounter] = useState(10)
setCounter(1000)

TypeScript类型补充

1.函数参数和返回值

// 给参数加上类型注解
// 给返回值加上类型注解(通常情况下可不写)
function total(num1: number, num2: number) :number{
​
  return num1 + num2
}

写了几个参数,必须传几个参数;不然会报错

image-20220211093041181.png

2.匿名函数参数类型

const names = ["abv", "tom", "jack"]
// 匿名函数可以不写参数类型
// item 类型根据上下文的环境推导出来的,因此可不写类型注解
names.forEach((item) => {
  console.log(item);
})

3.对象类型

// point : x, y
function printPoint(point: {x: number, y: number}) {
  console.log(point.x);
  console.log(point.y);
}
​
printPoint({x: 123, y: 456})

4.联合类型

| 联合符号: 表示并集,有两个或以上的类型组成

function printID(id: number | string) {
  // 使用联合类型的时候,需要注意不要直接对 参数进行指定类型的方法操作
  // 最好先对参数进行类型判断,再分段操作
  if(typeof id == "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id ++);
  }
}
// 可传 number 可以传 string
printID(1)
printID("abc")

5.可选类型

标识符 ? : 表示该变量是可选的(可传可不传)

// point : x, y 
// point 拥有第三个参数 z
// 使用 ?: 表示该变量是可选的(可传可不传)
function printPoint(point: { x: number, y: number, z?: number }) {
  console.log(point.x);
  console.log(point.y);
}
​
printPoint({ x: 123, y: 456 })
printPoint({ x: 1, y: 2, z: 3 })
​
export { }

可选类型和联合类型的关系

当参数是可选类型的时候;他其实本质上是一个: 类型 | undefined 的联合类型

function foo(message?: string) {
  console.log(message);
}
​
// 不传参,默认是传入undefined
foo()

6.类型别名

type 关键字:用于定义类型别名

type UnionType = number | string
type PointType = {
  x: number, 
  y: number, 
  z?: number
}
​
// function printPoint(point: { x: number, y: number, z?: number }) {
//   console.log(point.x);
//   console.log(point.y);
// }
function printPoint(point: PointType) {
  console.log(point.x);
  console.log(point.y);
  console.log(point.z);
  
}
​
printPoint({ x: 123, y: 456 })
printPoint({ x: 1, y: 2, z: 3 })
​
function printID(id: UnionType) {
  if(typeof id == "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(++ id);
  } 
}
​
printID(1)
printID("abc")

7.类型断言

类型断言: 将大范围的类具体化到指定类型

// 存在类型推导,可不写类型注解
const el = document.getElementById("app") as HTMLImageElement
​
el.src = "url"// 类继承:Person 是 student的父类
class Person { }
​
class Student extends Person {
  study() { }
}
​
// 宽泛的类型转化成具体的类型
function sayHello(p: Person) {
  (p as Student).study()
}
​
const stu = new Student()
sayHello(stu)
​
​
// 慎用 !!!!!
const message = "hello typescript"
const ann: number = message as any as number

8.非空类型断言

标识符 !. : 在变量后面放置,告诉typescript该变量不可能为空

// 不严谨,存在undefined,编译不通过
function foo(message?: string) {
  // 1. 逻辑代码块
  // if (message) {
  //   console.log(message.length);
  // }// 2. 告诉typescript,message不可能为空
  // 放在 可能为空的变量的后面 
  //  感叹号: 非空类型断言
  console.log(message!.length);
}

9.可选链

es11 的语法 ?. 可选链 表达式:当符号前者不为undefined的时候才去获取后面的值,如果符号前的对象为undefined,则返回undefined

type Person = {
  name: string,
  friend?:{
    name: string,
    age?: number
  }
}
​
const info:Person = {
  name: "tom",
  friend: {
    name: "jack"
  }
}
​
console.log(info.name);
// 如果符号前的对象为undefined,则返回undefined
console.log(info?.friend?.name);
console.log(info.friend?.age);

10. !! 运算符

运用 ! 取反运算符,双重使用将其他类型的变成boolean类型

const message = "hello typescript"// const flag = Boolean(message)
// 可以使用该方法简化操作,利用js!取反操作符
// 并不是ts新增的
const flag = !!message
console.log(flag);

11. ?? 运算符

es11 的新特性并不是ts新增的 ; || 短路或(左边为false,运算右边)类似,这更多用于if判断里面

逻辑操作符,当左边是 null 或者 undefined 则返回右侧的值

let message: string |null = nullconst content = message ?? "hello typescript"
// 同三元运算符
// message ? message : "hello typescript"
console.log(content);

12.字面量类型

// "Hello world" 也可以作为类型的,叫做字面量类型
const message: "Hello world" = "Hello world"
​
​
// 字面量类型的意义,就是必须结合联合类型
type Alignment = 'left' | 'right' | 'center'
let align: Alignment = 'left'
align = 'right'
align = 'center'// 报错
// align = "hhha"

13. 字面量推理

type Method = 'GET' | "POST"
function request(url: string, method: Method) {}
​
type Request = {
  url: string,
  method: Method
}
​
// 防止对象出错,可以在别名中嵌套别名(推荐)
const options: Request = {
  url: "https://www.gaoshi.org/jqk",
  method: "POST"
}
​
// 同样也可以使用断言
request(options.url, options.method as Method)