本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2022-06-29
需要注意的是,在 TypeScript 的函数类型定义中, =>
左边表示是输入类型,需要用括号括起来,右边是输出类型,与ES6箭头函数中的 =>
不是同一个概念。
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
return source.search(subString) !== -1;
}
用 ?
表示可选的参数。需要注意的是,可选参数必须接在必需参数后面。换句话说,可选参数后面不允许再出现必需参数了。
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
即 ...
的方式获取函数中的剩余参数。
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
});
};
let a: any[] = [];
push(a, 1, 2, 3);
...rest
中的 rest
是一个数组,由所有的剩余参数组成,rest参数只能是最后一个参数。
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
// 为什么不直接使用最后一个联合类型的写法呢,要加上两个重载呢
// 因为这样有一个缺点,就是不能精准的表达,可能会理解为 输入数字也能返回数字或字符串
TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义卸载前面。
数组类型有以下表示方式:
let fibonacci: number[] = [1, 1, 2, 3, 5];
let fibonacci: Array<number> = [1, 1, 2, 3, 5];
interface NumberArray {
[index: number]: number;
// 索引的类型为数字时,值的类型也得是数字
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
比如 argument
这个类数组,应该使用接口来表示类数组
function sum() {
let args: number[] = arguments;
}
// Type 'IArguments' is missing the following properties from type 'number[]': pop, push, concat, join, and 24 more.”
// 正确的用法 应该使用接口来表示
function sum() {
let args: {
[index: number]: number;
length: number;
callee: Function;
} = arguments;
}
// 或直接使用已有的类数组定义 比如 IArguments、NodeList、HTMLCollection
function sum() {
let args: IArguments = arguments;
}
// 而实际上 TypeScript帮我们定义的 IArguments 就是这样写的
interface IArguments {
[index: number]: number;
length: number;
callee: Function;
}
const list = [
{
name: 'jack',
age: 18
},
{
name: 'andy',
age: 20,
email: 'xxx'
}
]
function handleListItem(item: (typeof list)[number]) {
console.log(item)
}
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对对象的形状进行描述。
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
}
定义一个变量tom的类型为Person,也就约束了tom的形状必须和接口Person一致(少一些属性或多一些属性都是不允许的)。
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'Tom',
age: 25
}
let jerry: Person = {
name: 'jerry',
}
interface Person {
name: string;
age?: number;
[propName: string]: any;
}
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集。
// 错误
interface Person {
name: string;
age?: number;
[propName: string]: string;
// error 类型“number | undefined”的属性“age”不能赋给字符串索引类型“string”。
}
这里的索引属性就是任意属性,允许是 string
,但是可选属性的类型却是 number
,而 number
不是 string
的子集,
在一个接口中,只能定义一个任意属性,如果接口中有多个类型的属性,可以在任意属性中使用联合类型。
// 正确
interface Person {
name: string;
age?: number;
[propName: string]: string | number | undefined;
// 可选属性 等同于 age: number | undefined
}
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以使用 readonly
定义只读属性:
interface Person {
readonly id: number;
name: string;
age?: number;
}
let tom: Person = {
id: 89757,
name: 'Tom',
};
// error 无法分配到 "id" ,因为它是只读属性。
tom.id = 9527;
同时需要注意的是,只读属性也相当于确定属性,tom
如果是 Person
类,就一定要有 id
属性,且不能改变其值。