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']
}