TypeScript 的类型系统

85 阅读5分钟

基本类型

TypeScript 继承了 JavaScript 的类型,在这个基础上,定义了一套自己的类型系统。

js的基本类型包括如下8类

  • boolean
  • string
  • number
  • object
  • undefined
  • null
  • bigint
  • symbol

TypeScript 继承了以上8种类型看作其为基本类型。

undefined 和 null 既可以作为值,也可以作为类型取决于在哪里使用它们。

  1. boolean类型只包含truefalse两个布尔值。
  2. string类型包含所有字符串。
  3. number类型包含所有整数和浮点数。
  4. object 类型包含了所有对象、数组和函数。
  5. undefinednull 是两种独立类型,它们各自都只有一个值。undefined,表示未定义(即还未给出定义,以后可能会有定义)。null 类型也只包含一个值null,表示为空(即此处没有值)。
  6. bigint?
  7. symbol?

undefined补充 Snipaste_2024-07-23_20-49-40.png

Object 类型与 object 类型

大Object 类型

写的Object包含了所有可以转成对象的值,几乎所有的值。

image.png

除了undefinednull这两个值不能转为对象其他任何值都可以赋值给Object类型

空对象{}Object类型的简写形式

// let obj:{} == let obj:Object

小object 类型

只包含对象、数组和函数,不包括原始类型的值。

image.png

注意,无论是大写的Object类型,还是小写的object类型,都只包含 js 内置对象原生的属性和方法自定义对象的属性和方法都不存在于这两个类型之中。

这俩类型的自定义对象的属性和方法无法直接使用。

image.png

undefined 和 null 的特殊性

undefinednull既是值,又是类型

undefinednull,ts 允许了 null和undefined可以赋值给任意类型的变量,以便跟 JavaScript 的行为保持一致,

image.png 但是有时候,不利于发挥类型系统的优势。 image.png

TypeScript 提供了一个编译选项strictNullChecks

只要打开这个选项,undefinednull就不能赋值给其他类型的变量(除了any类型和unknown类型)。

值类型

TypeScript 规定,单个值也是一种类型,称为“值类型”。

image.png

值类型推断注意项

const声明变量,未宣告类型时

如果变量的值为原始类型则其值作为其类型;

如果是对象类型则不会作为值类型,因为js里面,const变量赋值为对象时,属性值是可以改变的

    // Uname推断为值类型'ws'
    const Uname = 'ws'
    // 推断为值类型'ws'const obj: {  name: string;  }
    const obj = {name:'王顺'}

联合类型

多种类型以或关系组合成的类型。

//phone可以为数字或字符类型
let phone:string | number = 123
//联合类型可以与值类型相结合
let sys:|'红'
        |'绿'
        |'蓝' = '红'
sys = '绿'
//可能为nulll类型的变量
let name:string|null;
name = 'John';
name = null;

如果一个变量有多种类型读取该变量时,往往需要进行“类型缩小”区分该值到底属于哪一种类型,然后再进一步处理。

function toUp (id:string|number) {
    //报错!!,因为不确定参数是否为字符类型。
    id.toUpperCase()
}

function toUp2 (id:string|number) {
    if(typeof id == 'string')id.toUpperCase()
    else{
        id = id + '' 
        id.toUpperCase()      
    }
}

function fn3 (rgb:'red'|'green'|'blue') {
    switch(rgb){
        case 'red':
            console.log('红色');
            return;
        case 'blue':
            console.log('蓝色');
            return;
    }
}
fn3('red')

交叉类型

多个类型以与的关系组成的一个新类型

叉类型常常用来为扩展对象类型

type a = {name:string}
type b = a &{age:number} 
let b:b = {age:10,name:'ws'}

type

type指自定义类型,可将相同类型约束复用。

let phone:number|string
let age:number|string

// type 
type StrOrNum = number|string
let phone:StrOrNum
let age:StrOrNum

type也可以约束对象类型

type obj = {name:string}
let ws:obj = {name:'ws'}

type不能重复定义 => 不能同类扩展 => 扩展需要另创type

image.png

type game = {
    type:string
}
type game = {
   class:string
}

type继承

type animal = {
    class:string
}
// type brid = animal
type brid = animal & {
    canFly:boolean
}

let luoluo:brid = {
    class:'鸟类',
    canFly:true
}

typeof 运算符

js下,typeof 返回操作值的类型 值为"字符串"

    //null 为空对象 ,所以属于object类型
    typeof undefined; // "undefined"
    typeof true; // "boolean"
    typeof 1337; // "number"
    typeof "foo"; // "string"
    typeof {}; // "object"
    typeof parseInt; // "function"
    typeof Symbol(); // "symbol"
    typeof 127n // "bigint"

ts下 typeof运算符主要参与类型运算,它返回操作值的ts类型,而不是字符串

类型运算的情况: 1变量直接宣告类型时,2定义类型时

    let data = {
        code:200,
        detail:{
            list:[{title:'xxx'}],
        }
    }
    
    // 变量宣告类型时
    let data2:typeof data = {       
        code:200,
        detail:{
            list:[{title:'xxx'}],
        }
    }
    // 定义类型时,定义的data类型采取data推断出的类型
    type data = typeof data
        let data3:data = {
            code:200,
            detail:{
                list:[{title:'xxx'}],
        }
    }

同一段代码可能存在两种typeof运算符,一种是类型运算,一种是值运算.

    let a = 1;
    let b:typeof a;
    if (typeof a === 'number') {
      b = a;
    }

由于编译时不会进行 JavaScript 的值运算,所以TypeScript 规定,typeof 的参数只能是标识符 不能是需要运算的表达式

块级类型声明

type具有块级作用域,同名type在不同域不冲突,其type在各自域生效

if(true){
    type aaa = number
}
if(true){
    type aaa = boolean
}
type aaa = string

类型的兼容

TypeScript 的类型存在兼容关系,某些类型可以包含其他类型.

如果类型A的值可以赋值给类型B,那么类型A就称为类型B子类型

父类兼容子类但子类不兼容父类,因为子类型继承了父类型的所有特征,所以可以用在父类型的场合。但是,子类型还可能有一些父类型没有的特征,所以父类型不能用在子类型的场合

// world类型可以赋值给string类型,则其为string类型的子类
type world = 'world'
let world:world = 'world'
// 父类兼容子类
let str:string = world
// 但子类不兼容父类
world = str //报错 不能将类型“string”分配给类型“"world"”。