TS 基础进阶

186 阅读6分钟

期望值是什么类型就赋值什么类型

基础类型

number、string、boolean、(Object、object、{})、array、null、undefined、 enum、tuple、any、unknown、void、symbol、never

  • nullundefined 是所有类型的子类型,可以把nullundefined赋值其他任意类型
  • any 相当于暴力通过类型检查,可以被任意类型赋值,也可以赋值给任意类型
  • unknown 可以被任意类型赋值,但只能赋值给unknownany类型的变量, ; 当进行了类型断言和类型推断之后,就可以赋值给其他任意类型的变量
function getAge() {
  let x: unknown
  return x
}
const age = getAge()
if (typeof age === 'string') {
  const getAge = age.toLowerCase()
}
  • void 常用函数返回值为空的情况
function getAge(): void {
  console.log('没有返回值')
}
  • never 常用来避免异常情况,目的就是写出类型绝对安全的代码
// 异常 
function error(msg: string): never { // 编译正确 
    throw new Error(msg);
} 
// 死循环 
function loopForever(): never { // 编译正确 
    while (true) {};
}
  • 数组
let arr: number[] = [1, 2, 3]
let arr1: Array<number> = [2, 4]
  • 元组(Tuple),元组类型是方括号里放置不同的类型
let arr: [number, string, boolean] = [1, 'tuple', true]

object 、Object 、{}

  • object object 类型用于表示所有的非原始类型,即我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。在严格模式下,null 和 undefined 类型也不能赋给 object。
let object: object;
object = 1; // 报错
object = "a"; // 报错
object = true; // 报错
object = null; // 报错
object = undefined; // 报错
object = {}; // 编译正确
  • Object

大 Object 代表所有拥有 toString、hasOwnProperty 方法的类型 所以所有原始类型、非原始类型都可以赋给 Object(严格模式下 null 和 undefined 不可以)

let bigObject: Object;
object = 1; // 编译正确
object = "a"; // 编译正确
object = true; // 编译正确
object = null; // 报错
ObjectCase = undefined; // 报错
ObjectCase = {}; // ok
  • {}

{} 空对象类型和大 Object 一样 也是表示原始类型和非原始类型的集合

enum枚举

初始值默认为 0 其余的成员会会按顺序自动增长 可以理解为数组下标

enum Color {
  RED,
  PINK,
  BLUE,
}

const red: Color = Color.RED;
console.log(red); // 0
  • 设置初始值
enum Color {
  RED = 2,
  PINK,
  BLUE,
}
const pink: Color = Color.PINK;
console.log(pink); // 3
  • 字符串枚举
enum Color {
  RED = "红色",
  PINK = "粉色",
  BLUE = "蓝色",
}

const pink: Color = Color.PINK;
console.log(pink); // 粉色
  • 常量枚举

使用 const 关键字修饰的枚举,常量枚举与普通枚举的区别是,整个枚举会在编译阶段被删除 我们可以看下编译之后的效果

const enum Color {
  RED,
  PINK,
  BLUE,
}

const color: Color[] = [Color.RED, Color.PINK, Color.BLUE];
console.log(color); //[0, 1, 2]

//编译之后的js如下:
var color = [0 /* RED */, 1 /* PINK */, 2 /* BLUE */];
// 可以看到我们的枚举并没有被编译成js代码 只是把color这个数组变量编译出来了

接口

我们常用接口的方式来表示对象的类型

interface Person {
  name: string
  age: number
  readonly tel: string // 属性前面加 readonly 表示属性只读
  height?: number // 属性后面加 ? 表示属性可选
  [prop: string]: any // 在接口的末尾写方括号,prop类型表示其他任意类型
}
let obj: Person = {
  name: '小明',
  age: 18,
  tel: '123456',
  weight: 55, // 新增的属性
}

类型别名

type count = number | number[]
function hello(value: count) {}

函数

我们需要给各参数定义类型,也需要给函数的返回值定义类型

function add(x: number, y: number): number {
  return x + y
}
// 参数后面加问号,表示类型可选
function add(x: number, y?: number): number {
  return y ? x + y : x
}
// 在类型后面赋值,表示默认值
function add(x: number, y: number = 0): number {
  return x + y
}

  • 接口方式定义函数类型
interface Add {
  (x: string, y: number): number
}
function add(x, y): Add {
  return x + y
}
  • 函数重载
type Types = number | string
function add(a: string, b: number): string
function add(a: number, b: string): string
function add(a: string, b: string): string
function add(a: number, b: number): number
function add(a: Types, b: Types) {
  if (typeof a === 'string' || typeof b === 'string') {
    return a.toString() + b.toString()
  } else {
    return a + b
  }
}

const result = add('1', 2)

泛型

泛型的语法是尖括号 <>方式来定义泛型, 里面写类型参数(用大写字母来表示),如果式多个参数用逗号分隔

// 单个参数
function getName<T>(name: T): T {
  return name
}

// 多个参数
function getValue<T, U>(arg: [T, U]): [T, U] {
  return arg
}

泛型约束

对于泛型我们经常添加一些约束条件,比如参数必须具有length属性,我们可以用extends的方式来添加约束条件

interface LengthObj {
  length: number
}
function getLength<T extends LengthObj>(arg: T): T {
  return arg
}
const str = getLength('aaa')
const obj = getLength({
  length: 5,
})

泛型接口

interface KeyValue<T, U> {
  key: T
  value: U
}
const person: KeyValue<string, number> = {
  key: 'order',
  value: 10,
}

联合类型

|(或)来表示联合

let value: number | string
value = 20
value = '联合类型'

交叉类型

&来表示交叉类型

interface A {
  name: string
  age: number
}
interface B {
  height: number
}
type AB = A & B
const person: AB = {
  name: 'dale',
  age: 18,
  height: 180,
}

类型推断

如果我们定义一个变量赋值,没有定义类型,程序就会依据值的类型来推断类型。 如果定义一个变量没有赋值,程序就会推断为any类型

let x = 1
x = true // 报错,x 必须为 number类型
x = 2 // 成功

类型断言

let str: any = '尖括号来做类型断言也可以用as类型的方式来做类型断言'
const len: number = (<string>str).length
const lenAs: number = (str as string).length

非空断言

变量后面加!,表示变量不为空

let user: string | null | undefined
console.log(user!.toUpperCase())

确定赋值断言

let value:number
console.log(value); // Variable 'value' is used before being assigned.

我们定义了变量, 没有赋值就使用,则会报错

通过 let x!: number; 确定赋值断言,TypeScript 编译器就会知道该属性会被明确地赋值。

let value!:number
console.log(value); // undefined 编译正确

类型守卫

程序难以判断参数中是否包含某个属性,这时候如果直接使用的话,就会报错。这时候就需要我们手动推断。

in

interface A {
  a: number
  x: string
}
interface B {
  a: number
  y: string
}
interface C {
  a: number
  z: string
}
function getValue(arg: A | B | C) {
  if ('x' in arg) {
    console.log(arg.x)
  }
  if ('y' in arg) {
    console.log(arg.y)
  }
  if ('z' in arg) {
    console.log(arg.z)
  }
}

typeof

function getValue(arg: number | string) {
  if(typeof arg === "number") {
    return 'number'
  }
  if(typeof arg === "string") {
    return "string"
  }
}

instanceof

function getValue(arg: Date | string) {
  if (arg instanceof Date) {
    return arg.getDate()
  } else {
    return new Date(arg).getDate()
  }
}

内置工具类型

Record

record作用:是将对象所有的属性转化为需要的类型

// 使用 Record 将各属性都变成字符串类型,然后就可以直接赋值给其他变量
type Property = 'user1' | 'user2';
type User = Record<Property, string>
const u: User = {
    user1: 'Da',
    user2: 'Xia'
}

Readonly

作用:将数组和对象的属性值转化为只读

interface User {
    name: string,
    age: number
}
let u: Readonly<User> = {
    name: 'Da',
    age: 18
}
u.name = 'Xia' // 报错

Required

作用:将类型的所有属性都变为必选

interface A {
  name?: string
  age?: number
}
const user: Required<A> = {
  name: 'a',
  age: 18,
}

Partial

作用:将类型的所有属性都变为可选

interface A {
  name: string
  age: number
}
const user: Partial<A> = {}

Extract

作用:提取联合类型中的某些类型

type B = number | string | boolean | symbol
let value: Extract<B, number | string> = 1

Exclude

作用:移除联合类型中的某些类型

type B = number | string | boolean | symbol
let val: Exclude<B, number> = '1'

Pick

作用:从类型中挑出一些类型

Omit

作用:从类型中移除一些类型

NonNullable

作用:去除类型中的null和undefined

Parameters

作用:获取函数的参数类型,组成元组类型

ReturnType

作用:获取函数的返回值类型