TS基础类型

55 阅读5分钟

1、基础类型

字符串

string,字符串类型

let name: string = 'penn'

数值

number,数值类型

let age: number = 12

布尔值

boolean,布尔值类型

let isMan: boolean = true

数组

使用类型[]或者Array<类型>表示

// 字符串数组
// 声明方式1
let arrStr: string[] = ['x1', 'x2'] 
// 声明方式2
let arrStr: Array<string> = ['x1', 'x2'] 

// 数值数组
// 声明方式1
let arrNum: number[] = [1, 2]
// 声明方式2
let arrNum: Array<number> = [1, 2]

元组

定义已知数量和类型的数组。

let arr: [number, string] = [1, 'name']

枚举

默认从0开始取值。

enum Color { Blue, Green, Red }

// Color.Blue -> 0
// Color[0] -> Blue

enum Color { Blue = 2, Green = 3, Red = 4 }

// Color.Blue -> 2
// Color[2] -> Blue

// Color JS对象
// {2: 'Blue', 3: 'Green', 4: 'Red', Blue: 2, Green: 3, Red: 4}

any

任意类型,当不知道当前对象具体有什么类型时,可以使用any来规避类型的检验。

let arr: any = 'name'

void

返回值为空,一般使用在函数的返回值类型,当没有返回值时,可使用void

undefinedvoid的子类型,因为undefined可以赋值给void

function fn(params): void {
  // ...
}

null 和 undefined

与JS的nullundefined对应,在非<font style="color:rgb(191, 65, 74);">--strictNullChecks</font>情况下,nullundefined是所有类型的子类型。

never

表示达不到终点,没有确定值。如报错,无限循环。都是没有最终值的。

可以用于代码完整性保护(即判断代码逻辑写完了没有)

// 报错 抛出异常
function fn(): never {
  throw new Error('error')
}

// 无限循环
function fn(): never {
  wile(1) {
    // ...
  }
}

// 代码完整性保护
function validateCheck(val: never) {}
function someTypeCheck(val: number | string | boolean) {
    if (typeof val === 'number') {
        return 1
    }

    if (typeof val === 'string') {
        return 2
    }

    if (typeof val === 'boolean') {
        return 3
    }

    // 如果val值类型没有全部判断,则会类型报错
    validateCheck(val)
}

object

对象类型,非原始类型的值都可以赋值。

let o: object = Object.create({})

设置某些固定属性名,其他随意,任意属性可以设置[propName: string]: anypropName只是一个变量,可以是任意值,如[a1: string]: any

let obj: { name: string, [propName: string]: any }

obj = { name: 'xx1', age: 1, work: () => {} }

类型断言

当需要一个类型值切换成自己想要的类型时,可是类型断言。

<>as都可表示类型断言。

let data: any = '123' 
// 确定data为字符串
console.log(<string>data.length)
console.log((data as string).length)

2、基本类型总结

unkownany的区别

相同点

都是可以赋值任何值,不会报错

不同点

any变量可以赋值给任意类型的变量

unkown不能赋值给任意类型的变量

3、接口

接口一般用来定义对象,函数,类。

使用Interface来定义对象的具体类型。

接口可重复定义,将属性进行合并,重复属性类型必须一样,否则会报错。

子类可以赋值给父类。

interface IParams {
  name: string
  age: number
  readonly height: number // 只读
  work?: string // 可选属性
  [propName: string]: any // 任意属性
}

let pramas: IParams = {
  name: 'penn',
  age: 100,
  height: 100,
  sex: 'man'
}

4、类型(type)

使用类型定义对象类型

type TParams = {
  name: string
  age: numebr
  readonly height: number // 只读
  work?: string // 可选属性
  [propName: string]: any // 任意属性
}

let pramas: TParams = {
  name: 'penn',
  age: 100,
  height: 100,
  sex: 'man'
}

类型与接口的区别

  • 类型不可重复定义,接口可以重复定义,并且会将类型相互合并。

5、类型断言

as

将变量声明成某种类型

是将大范围类型,断言成子类型

一般在变量有多种类型时,使用某种类型的方法时,需要直接声明该变量的具体类型才能使用这个方法

!

指定该变量一定不为空,一定是有值的。

function someTypeCheck(val: number | string | boolean | null) {
    // 使用 as 断言
    (val as string).charAt(1) 
    // 使用<>
    (<string>val).charAt(1) 

    // 使用! 指定该变量一定有值
    val!.toString()
}

6、函数类型声明

  • 函数式声明
  • 表达式声明

在函数中尽量少用this,使用this会导致类型推导不出来

如果需要定义this的类型,需要放在参数的第一位

function getObjKey1(this: { a: string, b: string }, key: 'a' | 'b') {
    return this[key]
}

// 表达式声明
const getObjKey1 = function (this: { a: string, b: string }, key: 'a' | 'b') {
    return this[key]
}

const obj = {
    name: 'penn',
    age: 18,
    hasWork: true
}

// typeof 提取对象的类型
type TObj = typeof obj

// keyof 提取对象的属性值
type TKey = keyof TObj

function getObjKey2(this: TObj, key: TKey) {
    return this[key]
}

函数声明重载

只能从子类型开始定义,且不能有具体实现,只是类型声明

function getData(val: number): number
function getData(val: string): string
function getData(val: number | string): number | string {
    return val
}

7、泛型

类型变量,当当前的对象类型不能确定,只有在创建或执行的时候才知道具体类型,这个时候就可以使用泛型。

一般都是使用大写字母表示,常用T

// 现在需要实现一个方法,输入一个构造函数,需要返回该构造函数的实例
class Women {
    constructor(public name: string) {}

}
class Man { 
    constructor(public name: string) {}
}

// 可用接口定义构造函数
interface IConstructor<T> {
    new (...args: any[]): T
}

// function getInstance<T extends new (...args: any[]) => any>(cls: T): InstanceType<T> {
// function getInstance<T>(cls: IConstructor<T>) {
function getInstance<T>(cls: new (name: string) => T, name: string) {
    return new cls(name)
}

在接口中定义泛型,泛型在接口右边表示未执行前就已经确定类型。泛型在属性左边表示,执行时才确认类型。

// 泛型在接口的位置
interface IFun<T> {
    <R>(a: T, b: R): T
}

泛型可以赋默认值<T = string>

interface IParams<T = string> {
  name: string
  data: T,
  length: number
}

泛型约束,限制泛型的类型在一定的范围只能,不是任意的。不限制默认就是任意类型。

使用extends限制泛型。

extends表示扩展,子类可以在父类的基础上进行扩展,但是一定要有父类的属性方法。

type TVal = string | number

interface IParams<T extends TVal> {
  name: string
  data: T,
  length: number
}

// 报错:类型“boolean”不满足约束“TVal”
const obj: IParams<boolean> = {
  name: '123',
  data: true,
  length: 2
}
// 写一个方法,获取对象的属性值
// 这样声明类型,只能限制一个对象,其他对象可能不适用
type TTarget = typeof obj1
type TKey = keyof TTarget
const getValue = (target: TTarget, key: TKey) => {
    return target[key]
}

// 通用写法
const getValue = <T extends object, K extends keyof T>(target: T , key: K) => {
    return target[key]
}



const obj1 = {
    name: 'px1',
    age: 18,
    hobby: ['football', 'basketball']
}

getValue(obj1, 'hobby')