1.交叉和联合类型
(1)交叉类型
格式: type1 & type2 & …
交叉类型是将多个类型合并为一个类型
let mergeFn = <T, U>(arg1:T, arg2:U):(T & U)=>{
let res = {} as (T & U);
res = Object.assign(arg1, arg2);
return res;
};
let res = mergeFn({name:'lnj'}, {age:18});
console.log(res);
(2)联合类型
格式: type1 | type2 | …
联合类型是多个类型中的任意一个类型
let value: (string | number);
value = 'abc';
value = 123;
2.类型保护
对于联合类型的变量,在使用时如何确切告诉编译器它是哪一种类型。
通过类型断言或者类型保护。
let getRandomValue = ():(string | number)=>{
let num = Math.random();
return (num >= 0.5) ? 'abc' : 123.123;
}
let value = getRandomValue();
console.log(value);
虽然通过类型断言可以确切的告诉编译器当前的变量是什么类型,
但是每一次使用的时候都需要手动的告诉编译器, 这样比较麻烦, 冗余代码也比较多。
let getRandomValue = ():(string | number)=>{
let num = Math.random();
return (num >= 0.5) ? 'abc' : 123.123;
}
let value = getRandomValue();
if((value as string).length){
console.log((value as string).length);
}else{
console.log((value as number).toFixed());
}
定义了一个类型保护函数, 这个函数的’返回类型’是一个布尔类型。
这个函数的返回值类型是, 传入的参数 + is 具体类型。
let getRandomValue = ():(string | number)=>{
let num = Math.random();
return (num >= 0.5) ? 'abc' : 123.123;
}
let value = getRandomValue();
function isString(value:(string | number)): value is string {
return typeof value === 'string';
}
if(isString(value)){
console.log(value.length);
}else{
console.log(value.toFixed());
}
除了可以通过定义类型保护函数的方式来告诉编译器使用时联合类型的变量具体是什么类型以外,我们还可以使用typeof来实现类型保护
注意点:
如果使用typeof来实现类型保护, 那么只能使用 === / !==,只能保护 number/string/boolean/symbol类型。
if(typeof value === 'string'){
console.log(value.length);
}else{
console.log(value.toFixed());
}
除了可以通过typeof类实现类型保护以外, 我们还可以通过instanceof来实现类型保护。
class Person {
name:string = 'lnj';
}
class Animal {
age: number = 18;
}
let getRandomObject = ():(Person | Animal)=>{
let num = Math.random();
return (num >= 0.5) ? new Person() : new Animal();
};
let obj = getRandomObject();
console.log(obj);
if(obj instanceof Person){
console.log(obj.name);
}else{
console.log(obj.age);
}
3.Null和undefined
TypeScript具有两种特殊的类型, null和 undefined,它们分别具有值null和undefined。
默认情况下我们可以将 null和 undefined赋值给任意类型;null和 undefined也可以相互赋值;
注意点: 在企业开发中, 如果不想把 null和 undefined赋值给其它的类型;或者不想让 null和 undefined相互赋值, 那么我们就可以开启strictNullChecks。
let value1:null;
let value2:undefined;
value1 = value2;
value2 = value1;
let value3:number;
value3 = value1;
value3 = value2;
如果我们开启了strictNullChecks, 还想把null和 undefined赋值给其它的类型。
那么我们就必须在声明的时候使用联合类型。
let value:(number | null | undefined);
value = null;
value = undefined;
对于可选属性和可选参数而言, 如果开启了strictNullChecks, 那么默认情况下数据类型就是联合类型,就是当前的类型 + undefined类型。
class Person {
name?:string
}
function say(age?:number) {
}
去除 null或 undefined检测:
function getLength(value:(string | null | undefined)) {
value = 'abc';
return ()=>{
// return value.length; // 报错
// return (value || '').length;
// return (value as string).length;
// 我们可以使用!来去除null和undefined
// !的含义就是这个变量一定不是null和undefined
return value!.length;
}
}
let fn = getLength('www.it66.com');
let res = fn();
console.log(res);
4.类型别名
(1)什么是类型别名
类型别名就是给一个类型起个新名字, 但是它们都代表同一个类型。
给string类型起了一个别名叫做MyString, 那么将来无论是MyString还是string都表示string
type MyString = string;
let value:MyString;
value = 'abc';
value = 123; //报错
value = false; //报错
(2)类型别名也可以使用泛型
type MyType<T> = {x:T, y:T};
let value:MyType<number>;
value = {x:123, y:456};
value = {x:'123', y:456};
value = {x:false, y:456};
(3)可以在类型别名类型的属性中使用自己
type MyType = {
name:string,
// 一般用于定义一些树状结构或者嵌套结构
children?:MyType
}
let value:MyType = {
name:'one',
children:{
name:'one',
children:{
name:'one',
}
}
}
(4)接口和类型别名是相互兼容的
type MyType = {
name:string
}
interface MyInterface {
name:string
}
let value1:MyType = {name:'lnj'};
let value2:MyInterface = {name:'zs'};
value1 = value2;
value2 = value1;
5.类型别名和接口异同
(1)都可以描述属性或方法
type MyType = {
name:string;
say():void;
}
interface MyInterface {
name:string;
say():void;
}
(2)都允许拓展
interface MyInterface {
name:string;
say():void;
}
interface MyInterface2 extends MyInterface{
age:number;
}
let value:MyInterface2 = {
name:'lnj',
age:18,
say():void{
}
}
type MyType = {
name:string;
say():void;
}
type MyType2 = MyType & {
age:number;
}
let value:MyType2 = {
name:'lnj',
age: 18,
say():void{
}
}
(3)type 可以声明基本类型别名,联合类型,元组等类型, interface不能
type MyType1 = boolean;
type MyType2 = string | number;
type MyType3 = [string, boolean, number];
(4)type不会自动合并
interface MyInterface {
name:string
}
interface MyInterface {
age:number
}
let value:MyInterface ={
name:'lnj',
age:18
}
type MyType = { //报错
name:string
}
type MyType = { //报错
age:number
}
6.字面量类型
字面量就是源代码中一个固定的值
例如数值字面量: 1,2,3,… 例如字符串字面量: ‘a’,‘abc’,…
当使用字面量作为具体类型时, 该类型的取值就必须是该字面量的值。
type MyNum = 1;
let value1:MyNum = 1;
let value2:MyNum = 2; //报错,只能是1
7.可辨识联合
具有共同的可辨识特征。一个类型别名, 包含了具有共同的可辨识特征的类型的联合。
interface Square {
kind: "square"; // 共同的可辨识特征
size: number;
}
interface Rectangle {
kind: "rectangle"; // 共同的可辨识特征
width: number;
height: number;
}
interface Circle {
kind: "circle"; // 共同的可辨识特征
radius: number;
}
Shape就是一个可辨识联合
因为: 它的取值是一个联合,这个联合的每一个取值都有一个共同的可辨识特征
type Shape = (Square | Rectangle | Circle);
function aera(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.width * s.height;
case "circle": return Math.PI * s.radius ** 2; // **是ES7中推出的幂运算符
}
}