TS类型全解

 使用TypeScript开发的程序更安全,常见的错误都能检查出来。TS能让程序员事半功倍。而原因在于TS的“类型安全”(借助类型避免程序做无效的事情)。

图 运行程序的过程

但是TS不会直接编译成字节码,而是编译成JavaScript代码。TS编译器生产AST后,先对代码做类型检查,然后再编译成JavaScript代码。

TS类型全解_第1张图片

图 TS运行程序的过程

1 类型

类型是指一系列值及对其执行的操作。

TS类型全解_第2张图片

图 TS的类型层次结构

TS具有自动推导类型的功能:

let num1 = 1; // 推导为number类型

我们可以不要显式的指明num1为number类型(let num1:number = 1),这是一种推荐的写法。

1.1 unknown与any

unknown

表示任何值,但是TS会要求你再做检查,细化类型。

any

表示任何值,TS不会做检查,应尽量避免使用。

表 unknown与 any的对比

unknown类型的值可以比较(使用==、===、||、&&和?)、可以否定(使用!)及可以使用typeof和instanceof。

let a: unknown = 30; //unknown

let b = a === 123; // boolean

let c = a + 10; //Error,Object is of type ‘unknown’

if (typeof a === ‘number’) {

  let d = a + 10; // number

}

unknown的用法如下:

1)TS不会把任何值推导为unknown类型,必须显示注解。

2)unknown类型的值是可以比较。

3)操作时不能假定unknown类型的值为某种特定类型,必须先向TS证明这个值确实是某个类型。

any 应尽量避免使用。在极少数情况下,any将发挥作用:

let a: any = 66;
let b: any = ['danger'];
let c = a + b; // string 66danger 如果上面不显式指明为any类型,则会报编译错误

1.2 boolean

boolean类型有两个值:true和false。该类型的值可以比较(==、===、||、&&和?)、可以否定(!)。用法如下:

let a = true; // boolean
const b = true; // ture
let c: boolean = false; // boolean
let d: true = true; // true
let e: true = false; // error Type false is not assignable to type true

1.2.1 推导类型的四种方式

1)让TS推导出值的类型为boolean(a)。

2)让TS推导出值为某个具体的布尔值(b)。

3)明确告诉TS,值的类型为boolean(c)。

4)明确告诉TS,值为某个具体的类型值(d和e)。

第四种情况,称为类型字面量。即仅表示一个

let a: object = {
    x: 'a'
};
a = {name:'212'};
console.log(a); // {x:'212'}
a = false; // error Type boolean is not assignable to type object
a.name; // error,Property name does not exist on type object

let b: Object = {
    name: 'b'
};
b = true;
b.name; // Property name does not exist on type Object

值的类型。注意,这种情况下也仍需为变量赋值,否则变量为空。

1.3 对象

object

接受所有引用类型,除基本类型(string、number、boolean、undefined和null)外,都可以赋值给它。

Object

是一个通用类型,可以被赋予任何类型的值。赋值以后能改变类型。

{}

Object的别名。

表 object、Object与{}

这三种只能表示该值是一个JS对象,范围比较窄,尽量避免使用。

1.3.1 对象字母量

上面的a指定为object类型后,在引用属性name时提示并没有该字段。这时,我们可以采用让TS自行推导的方式:

let a = {
    name: 'hello'
}; //类型为 {name: string}
console.log(a.name); // hello

这种声明对象类型的方式称为对象字面量句法(“这个东西的结构是这样的”)。可以让TS推导对象结构,也可以在花括号内明确描述:

let a: {name: string} = {
    name : 'a'
};
a = {
    name: "b"
};

a = {
    name: 'c',
    age: 17 // error Type { name: string; age: number; } is not assignable to type { name: string; }
}

如果先声明变量,然后在初始化,TS将确保在使用该变量时已经明确为其赋值了。

1.3.2 属性可选

let a: {
    att1: number,
    att2?: string, //该属性可以没有
    [key: number]: boolean // 可能有任意多个数字属性,其值为boolean类型。(key这个名字可以是任意的)
}
a = {att1: 1};
a = {att1: 2, att2: 'hello'};
a = {att1: 1, 1: true,2: false};

上面[key:T]: U 句法称为索引签名,通过这种方式告诉TS,指定的对象可能有更多的键。键的类型为T,值的类型为U。其中T必须为number或string类型。key可以是任意名称。

1.4 数组与元组

TS支持两种注解数组类型的句法:T[]和Array。两者作用和性能无异。

let arr: string[] = ["hello","TS"];
let arr2: Array = ["hello","TS"];
let arr3: any[] = [1,"hello",false]; // 一般情况,数组应该保持同质,即类型一样

any[]离开定义时所在的所用域后,TS将最终确定一个类型,不再扩张。

function buildArr() {
    let a = []; // any[]
    a = [1,false];
    return a;
}

let newArray = buildArr();
newArray.push(2);
newArray.push("hello"); // 运行时报错 Argument of type '"hello"' is not assignable to parameter of type 'number | boolean'

1.4.1 元组

元组是array的子类型。长度固定,各索引位的值具有固定的已知类型。与其他类型不同,声明元组时必须显式注解类型:

let a: [string,number,boolean];

元素也支持可选的元素(?表示可选)。也支持剩余元素,即为元组定义最小长度:

let a: [string,boolean?];
a = ["hello"];
a = ['hello', false];

let b: [boolean,...string[]];
b = [true];
b = [true,'hello'];

1.4.2 只读数组和元组

let a: readonly string[] = ["a","b","c"];
a.concat("s");
console.log(a.concat("s")); // [ 'a', 'b', 'c', 's' ]
console.log(a); // ["a","b","c"];
a.push("x"); // Property push does not exist on type readonly string[]

若想更改只读数组,使用非变型方法,例如.concat和.slice。不能使用可边型方法,例如.push和.splice。

1.5 其他类型

处理较长的数字时,为了便于标识数字,建议使用数组分隔符:

let a = 1_000_000
let c : 1_233_344 = 1_233_344; //注意,这里对c一定要赋值,如果是:let c : 1_233_344,这样值为空

null

缺少值。

undefined

尚未赋值的变量。

void

没有return语句的函数。

never

永不返回的函数。

表 TS中的空值

1.5.1 枚举

使用枚举极易导致安全问题,建议远离枚举。

1)枚举可以分几次声明:

enum Language {
    Chinese,
    English
}
enum Language {
    Russian = 2 //此时必须为这个枚举指定一个与上面枚举值不同的值
}
console.log(Language[1]); // English
console.log(Language.English); // 1
// Language:
// {
//     '0': 'Chinese',
//     '1': 'English',
//     '2': 'Russian',
//     Chinese: 0,
//     English: 1,
//     Russian: 2
// }

2)枚举值可以混用字符串和数字。(在枚举中,尽量不要使用数字,否则可能会置枚举于不安全的境地。)

enum Language {
    Chinese= 1,
    English= 'e'
}
// { '1': 'Chinese', Chinese: 1, English: 'e' }

3)为避免不安全的访问操作,可以通过const enum指定枚举的安全子集。来限制只能通过字符串来访问。

enum Language {
    Chinese= 1,
    English= 'e'
}
console.log(Language[3]); // undefined 可以访问,这样操作不安全。

const enum Language2 {
    Chinese= 1,
    English= 'e'
}
Language2[2]; //error const类型只能通过字符串类型访问,即Language2.Chinese

2 语言特性

2.1 类型别名 type

可以使用变量声明(let、const)为值声明别名,类似的,可以为类型声明别名:

type Age = number; // number的别名为Age

这样可以减少重复输入复杂的类型及更清楚地表明变量的作用。

别名具有以下特性:

1)使用别名的地方都可以替换成源类型。

2)同一个类型别名不能声明两次。

3)别名采用块级作用域。内部的类型别名将掩盖外部的类型别名。

type Age = 18;
{
    type Age = string;
}
type Age = boolean; // Duplicate identifier Age

2.2 并集和交集

type A = {name: string,age: number};
type B = {name: string,file: boolean};
type C = A | B;  // {name: string,age:number,file: boolean}
type D = A & B; // {name: string}

你可能感兴趣的:(TypeScript编程,typescript,javascript,node.js,前端框架,前端)