类型推论
如果没有明确指定变量的类型,那么TypeScript就会自动去其推断变量的类型。
注意:定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查
let myFavoriteNumber = "seven";
// 提示你:不能将类型“number”分配给类型“string”
myFavoriteNumber = 7;
联合类型
联合类型表示你可以给变量定义多种类型,使用 |
分隔符来进行分割
// 联合类型 (表示age有可能是number也有可能是string类型的)
const age: number | string = 20;
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
function getLength(something: string | number): string {
// TS会提示你 类型“string | number”上不存在属性“length”。类型“number”上不存在属性“length”
return something.length;
// 此时我们只能访问到 .toLocaleString() .toString() .valueOf() 方法,因为这在string 和 number都存在
}
联合类型的变量在被赋值的时候,会根据类型推论的规则自动推断出其类型
const favoriteNumber: string | number = 78.45678;
// 自动推断出为联合类型的 number 类型
console.log(favoriteNumber.toFixed(2));
// 那么之后去调用 number 没有的方法或属性就会报错
console.log(favoriteNumber.length);
函数
一个函数有输入或输出,在TS中对其输入和输出进行类型上的约束,需要把输入和输出都考虑到
为函数定义类型方式如下:
写法如下:
function getSumNumber(x: number, y: number): number {
return x + y;
}
函数表达式(匿名函数)定义类型写法如下
let getSumFunction = function(x: number, y:number): number {
return x + y;
}
上面这个是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 getSumFunction
,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 getSumFunction
添加类型,则应该是 如下这样的写法:
let getSumFunction: (x: number, y: number) => number = function(x: number, y:number): number {
return x + y;
}
这个代码表示getSumFunction 是这个类型 (x: number, y: number) => number, 所以后面写的匿名函数必须按照这个类型的规范去写。
可选参数和默认参数
可选参数注意点如下:
- 在TypeScript里的每个函数参数都是必须的
- 在JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined
- 在TypeScript里我们可以在参数名旁使用?实现可选参数的功能
- 可选参数必须在必选参数的后面
function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return firstName + "-" + lastName;
}
return firstName;
}
默认参数注意点如下:
- 与可选参数不同的是,带默认值的参数不需要放在必须参数的后面。如果带默认值的参数出现在必须参数前面,用户必须明确的传入 undefined值来获得默认值
function buildName(firstName: string, lastName: string = "Cat"): string {
if (lastName) {
return firstName + " " + lastName;
}
return firstName;
}
剩余函数
有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。在JS里可以使用 arguments
来访问所有传入的参数。而在TypeScript里,我们可以把所有参数收集到一个变量里
剩余参数会被当做个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 编译器创建参数数组,名字是你在省略号( ...
)后面给定的名字,你可以在函数体内使用这个数组。
function buildName(firstName: string, ...restOfName: string[]) {
console.log(restOfName);
// [ 'Samuel', 'Lucas', 'MacKinzie' ]
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
console.log(employeeName);
// Joseph Samuel Lucas MacKinzie
接口
在 TypeScript 中,可以使用接口来 定义对象中属性的各个类型。 在 TypeScript 里接口的作用就是为这些类型命名和为代码或第三方代码定义契约。
简单的Demo
// IPerson接口
interface IPerson {
username: string;
age: number;
sex: number;
}
// 对象定义为是一个IPerson的类型,就必须实现接口当中的属性
const Tom: IPerson = {
username: "Tom",
age: 20,
sex: 1,
};
可选属性
接口里的属性不全都是必需的,定义方式如下:
interface IPerson {
name: string;
age: number;
sex?: number; // 可选属性
}
// 这时我们 有一个 对象 需要去实现 IPerson 这个接口
const tom: IPerson = {
name: "Tom",
age: 21,
};
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly
定义只读属性。之后去修改只读属性就会报错。
interface IPerson {
readonly id: number; // 只读属性
name: string;
age: number;
}
// 这时我们 有一个 对象 需要去实现 IPerson 这个接口
const tom: IPerson = {
id: 20211027,
name: "Tom",
age: 21
};
任意属性
有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
prop 被定义为 string 类型,可以返回 any 类型,此时在实现该接口时 在定义 name、age属性、sex属性为可选属性之后,用户可以随意定义接口中没有的属性。
interface IPerson {
name: string;
age: number;
sex?: number; // 可选属性
[prop: string]: any; // 任意属性
}
// 这时我们 有一个 对象 需要去实现 IPerson 这个接口
const tom: IPerson = {
name: "Tom",
age: 21,
gender: "male",
};
接口描述函数(函数类型)
接口能够描述JavaScript中对象拥有的各种各样的外形。 除了描述带有属性的普通对象外,接口也可以描述函数类型。
// 定义ISearchFunc接口
interface ISearchFunc {
(source: string, subString: string): boolean;
}
// 定义一个函数实现这个接口
let mySearch: ISearchFunc = function (source: string, subString: string) {
let result = source.search(subString);
if (result == -1) {
return false;
}
return true;
};
注意点:
- 函数的参数名不需要与接口里定义的名字相匹配,可以不匹配的。
接口描述数组
interface IStringArray {
[index: number]: string
}
let myArray: IStringArray = ["Bob", "Fred"];
接口描述类(类类型)
通过接口也可以实现对类的属性或方法进行某种契约
interface ClockInterface {
currentTime: Date; // 定义变量
setTime(d: Date); // 定义方法
}
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
扩展接口
和类一样,接口也可以相互扩展相互继承的。 这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
let square: Square = {
color: "blue",
sideLength: 20
}
数组类型定义表示方式
类型[] 表示法
// 类型[] 表示法
const numberArray: number[] = [1, 3, 5, 7, 9];
数组泛型
// 数组泛型
const numberArray2: Array<number> = [1, 3, 5, 7];
用接口描述数组
INumberArray
表示:只要索引的类型是数字时,那么值的类型必须是数字。
虽然接口也可以用来描述数组,但是我们一般不会这么做,因为这种方式比前两种方式复杂多了。
// 用接口表示数组
interface INumberArray {
[index: number]: number;
}
const numberArray3: INumberArray = [1, 3, 5, 7, 9, 11];