TypeScript中 类型详解( 数组、联合类型、类型别名、对象、函数、void 、Null 和 Undefined、Never、接口 interface )

传送门:TypeScript 中文网

1. 数组类型

TypeScript 像 JavaScript 一样可以操作数组元素。 有两种方式可以定义数组。
第一种,可以在元素类型后面接上 [ ],表示由此类型元素组成的一个数组:

let list: number[] = [1, 2, 3];
let objList: object[] = [{
    
     name: '张三', age: 18 }];

第二种方式是使用数组泛型,Array<元素类型>:

let list: Array<number> = [1, 2, 3];
let objList: Array<object> = [{
    
     name: '张三', age: 18 }];

2. 联合类型

数组中既有 number 类型又有 string 类型,可以用 | 分割多个类型

let str: string | number = 1;
str = '张三';

如果数组中可以是字符串或者数字,则可这么写

let arr: Array<number | string> = [1, 2, 'TS'];

3. 类型别名

当一个复杂类型或者联合类型过多或者被频繁使用时,可通过类型别名来简化该类型的使用
用法:type 名称 = 具体类型

type CustomArray = Array<number | string>;
let arr: CustomArray = [1, 2, 'TS'];

以上代码中,type 作为创建自定义类型的关键字

  • 类型别名可以是任意合法的变量名称;
  • 推荐大驼峰的命名写法;

4. 对象类型

使用 { } 来描述对象结构;
语法:{ 属性名: 属性值, 属性名: 属性值 };
函数可采取:方法名(): 返回值类型 或者 函数名: Function(不指定返回值)的形式

let obj: {
    
    
  name: string,
  sayHello: Function,
} = {
    
    
  name: 'TS',
  sayHello() {
    
    },
};

使用类型别名
直接使用 { } 会降低代码可读性,不具有辨识度,推荐使用类型别名添加对象类型;

type obj = {
    
    
  name: string;
  sayHello(): string;
};
 
const p: obj = {
    
    
  name: 'TS',
  sayHello() {
    
    
    return this.name;
  },
};

带有参数的方法的类型
如果对象中的函数带有参数,可在函数中指定参数类型;

type obj = {
    
    
  name: string;
  sayHello(word:string): string;
  eatFood: (food:string) => string;
};
const p: obj = {
    
    
  name: 'TS',
  sayHello(word) {
    
    
    return word;
  },
  eatFood(food){
    
    
    return `我爱吃${
      
      food}`;
  }
};
p.sayHello('hi');
p.eatFood('牛肉');

对象可选属性
在属性名后边加上 ?,表示属性是可选的;

type obj = {
    
    
  city: string,
  age?: number,
}
const p:obj = {
    
     city: '南京', age: 24};

type config = {
    
    
  method?: string;
  url: string;
};
const func = (params: config) => {
    
    };
func({
    
     url: '/user' });
// [propName:string]:any,表示该对象里必须要有 city 属性外,其他任意属性都可;
type obj = {
    
    
  city: string,
  [propName:string]:any,
}
 
const p:obj = {
    
    
  city: '南京',
  age: 24,
  name:'明天也要努力',
}

5. 函数类型

函数类型需要指的是: 函数参数返回值 的类型,分为两种写法 :

  • 单独指定参数,返回值类型;
// 单独指定函数返回值和函数参数
function add(num1: number, num2: number): number {
    
    
  return num1 + num2;
}
// 指定变量形式的
const add2 = (num1: number, num2: number): number => {
    
    
  return num1 + num2;
};
  • 同时指定参数和返回值
// 同时指定参数和返回值
type CustomFunc = (num1: number, num2: number) => number;
 
const add3: CustomFunc = (num1, num2) => {
    
    
  return num1 + num2;
};

注意: 当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型,这种形式只适用于函数表达式。

6. void 类型

某种程度上,void 类型像是与 any 类型相反,表示没有任何类型。 当函数没有返回值时,通常会见到其返回值类型是 void:

function warn():void{
    
    
  console.log("warning message");
};

声明 void 类型的变量没什么大用,因为只能为它赋予 undefined 和 null;

let a: void = undefined;

7. Null 和 Undefined

TypeScript 里,undefined 和 null 各自有自己的类型分别:undefined 和 null。 和 void 相似,它们的本身的类型用处不是很大:

let u: undefined = undefined;
let n: null = null;

默认情况下 null 和 undefined 是所有类型的子类型(可把 null 和 undefined 赋值给 number 类型的变量)。
然而,当指定 --strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自。 这能避免很多常见的问题。 也许在某处想传入 string 或 null 或 undefined,可使用联合类型 string | null | undefined。

const num: number = undefined;
const str: string = null;

let value: string | undefined | null = null;
value = 'hello';
value = undefined;

8. Never

never 类型表示的是那些永不存在的值的类型,never 类型是任何类型的子类型,也可以赋值给任何类型;
然而没有类型是 never 的子类型或可赋值给 never 类型(除了 never 本身之外,并且即便 any 也不能赋给 never);
一般用在不可能运行到 return 的函数里面

// 抛出异常的函数永远不会有返回值
function error(message: string): never {
    
    
  throw new Error(message);
}
// 死循环的函数不会有返回值
function infiniteLoop(): never {
    
    
  while(true) {
    
     }
}
function sayHi(): never {
    
     
  sayHi();
}

// 空数组,而且永远是空的
const empty: never[] = [];

never 的一种实用方式是用于全面性检查;

type Foo = string | number;

function controlFlowAnalysisWithNever(foo: Foo) {
    
    
  if (typeof foo === "string") {
    
    
    // 这里 foo 被收窄为 string 类型
  } else if (typeof foo === "number") {
    
    
    // 这里 foo 被收窄为 number 类型
  } else {
    
    
    // foo 在这里是 never
    const check: never = foo;
    throw new Error();
  }
}

一开始按照逻辑在 else 分支里,foo 只能是 never 类型,哪天改了 Foo 类型

type Foo = string | number | boolean;

必然引起 else 分支的编译错误。内置的 Exclude 类型操作也利用了 never;

type Exclude<T, U> = T extends U ? never : T;
type T = Exclude<boolean | string, string>; // type T = boolean

看一下 never 和其他类型一起操作的结果,这个结果也会用到后面介绍的类型操作里。

type NeverTest = string | never // string
type NeverTest2 = string & never // never

5. 接口 interface

当一个对象类型被多次使用时,一般使用接口(interface)描述对象的类型,达到复用的目的;

  • 使用 interface 关键字来声明接口;
  • 接口名称推荐以 I 为开头;
  • 声明接口之后,直接使用接口名称作为变量的类型;
interface IPeople {
    
    
  name: string;
  age: number;
  sayHello(): void;
}
 
let p: IPeople = {
    
    
  name: '张三',
  age: 18,
  sayHello() {
    
    },
};

接口继承
如果两个接口之间有相同的属性和方法,可将公共的属性和方法抽离出来,通过继承来实现复用;

interface A {
    
    
  name: string;
};

interface B extends A {
    
    
  age: number;
  eat:() => string;
};

let person:B = {
    
    
  name: '明天也要努力',
  age: 27,
  eat: () => {
    
    return '薯条' }
}

定义函数类型

interface Fn {
    
    
  (val: number): string[]
}

const fn:Fn = function (val:number){
    
    
  return ['JS','TS']
}

猜你喜欢

转载自blog.csdn.net/ZYS10000/article/details/130949053