在TypeScript中,数组的定义如下:
let fibonacci: number[] = [1,2,3,4,5]
上面的🌰中,不允许出现除number以外的类型,比如:
let fibonacci: number[] = [1,2,3, true]
这样写会抛出异常不能将类型“(number | boolean)[]”分配给类型“number”
数组的方法也会根据数组在定义时的类型约定,受到限制,举个🌰
let fibonacci: number = [1,2,3,4]
fibonacce.push(true)
这样写也不行,会抛出错误不能将类型“number[]”分配给类型“number”
&& 不能将类型“number[]”分配给类型“number”
举个🌰
interface NumberArray {
[index: number]: number;
}
let fibonacce: NumberArray = [1,2,3,4]
NumberArray
:索引是数字时,值的类型必须用数字。
一般不会用这个去定义一个数组。
类数组不能用数组定义的方式去赋值,举个🌰
function sum() {
let args: number[] = arguments;
}
这样写会抛出错误类型“IArguments”缺少类型“number[]”的以下属性: pop, push, concat, join 及其他 24 项
因为类数组并没有数组原型上的方法,pop等等,所以如果用array去定义,那么类型校验不通过,我们可以用IArguments
类型去定义一个类数组,举个🌰:
function sum() {
let agrs: IArguments = arguments;
}
类型IArguments
其实就是一个interface
,是TypeScript内置的类型,相当于这样写:
interface IAgruments {
[index: number]: any;
length: number;
callee: function;
}
除此之外,TypeScript中还有很多内置的类型,比如NodeList
,HTMLCollection
等
无限制的数组项,举个🌰
let list: any[] = [1, '1', true, {name: '1'}, [3,4,5]]
完全ok!
TypeScript中函数的定义如下:
function sum(x: number, y: number): number {
return x + y
}
let sum = function(x: number, y: nunmber): number {
return x + y
}
sum并没有类型的定义,可以给sum也加一个定义:
let sum: (x: number, y: number) => number = function(x: number, y: number): number {
return x + y
}
上面所有的定义中,函数的参数都是必传的,不能少,也不能多,比如这样:
再比如,这样:
与接口中的可选属性类似,用?
表示,举个🌰:
let buildName: (f: string, l?: string) => string = function (
firstName: string,
lastName?: string
): string {
if (lastName) return firstName + " " + lastName;
return firstName;
};
console.log(buildName("Alice"));
console.log(buildName("Alice", "Yan"));
需要注意的是,可选参数必须在最后面,也就是说,可选参数的后面,不能再接必需参数,像这样就不行:
TypeScript会将添加了默认值的参数自动设置为可选参数,举个🌰
function buildName(firstName: string, lastName: string = 'Yan'): string {
return firstName + ' ' + lastName
}
console.log(buildName('Alice'))
此时就不受「可选参数必须在必须参数后面」的限制了
...rest
获取剩余参数
function push(array: any[], ...items: any[]) {
items.forEach( item => array.push(item))
}
用于手动指定一个值的类型
(推荐)
值 as 类型
or
(不推荐)
<类型> 值
TypeScript不确定一个联合类型的变量到底属于哪个类型的时候,只能访问此联合类型的所有类型中共有的属性或方法,比如之前说的string
| number
访问toString
,再举个栗子:
interface Dog {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function getName(animal: Dog | Fish) {
return animal.name
}
有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法,举个栗子:
interface Dog {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Dog | Fish) {
if( typeof animal.swim === 'function' ) return true
return false
}
上面这个栗子就会抛出错误类型“Dog | Fish”上不存在属性“swim”
这个时候我们就可以用类型断言
,将animal
断言成Fish
:
interface Dog {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Dog | Fish): boolean {
if(typeof (animal as Fish).swim === 'function') return true
return false
}
📢注意:类型断言只能够【欺骗】TypeScript编译器,无法避免运行时的错误,滥用类型断言可能会导致运行错误,举个栗子:
interface Dog {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function goSwim(animal: Dog | Fish): void {
(animal as Fish).swim()
}
const tony: Dog = {
name: 'Tony',
run() { console.log('im run!')}
}
swim(tony)
当类之间有继承关系时,类型断言也是很常见,举个栗子:
class ApiError extends Error {
code: number = 0;
}
class HttpError extends Error {
statusCode: number = 200;
}
function isApiError(error: Error) {
if( typeof (error as ApiError).code === 'number') return true
return false
}
这个栗子中,声明了函数`isApiError`,用来判断传入的参数是不是`ApiError`类,但是由于父类`Error`中并没有`code`这个属性,所以直接使用就会报错,就要使用`as`进行`类型断言`
any
这其实就是有一点不靠谱了,咱就是整个就是说你定义一个类型是number
,但是如果你又觉得他好像不是number
,那你可以把他再断言成any
,举个栗子:
const foo: number = 1
foo.length = 1
这样写是不能通过编译的,因为foo
是number
类型,是没有length
属性的,所以TypeScript给了提示类型“number”上不存在属性“length”。
,这种提示非常有效!
但是有时候我们的写法是完全没有问题的,比如:
window.foo = 1
在js中,这种写法完全ok,给window
添加属性foo
,值为1
,但是,在TypeScript中是不支持的,它会抛出这个错误类型“Window & typeof globalThis”上不存在属性“foo”。
,这时候我们就可以用类型断言,把window
断言成any
,any
类型上,访问任何属性都是允许的,像这样:
(window as any).foo = 1
ok
举个栗子:
function getCacheData(key: string): any {
return (window as any).cache[key]
}
上面的例子中,getCacheData
返回的类型是any,我们不确定他到底返回的是什么类型,所以当我们使用这个function的时候,我们可以根据自己的需要,对他的返回值进行断言,举个栗子:
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData('tom') as Cat;
tom.run()
并不是所有的类型都能够相互断言,只有A
包含B
的所有属性,或者B
包含A
的所有属性,A
和B
才能相互断言,举个栗子:
interface Animal {
name: string;
}
interface Cat {
name: string;
run(): void;
}
let tom: Cat = {
name: "tom",
run() {
console.log("i can run");
},
};
let anmimal: Animal = tom;
tom.run();
(anmimal as Cat).run();
如果我们加一个新的interface:
let coffeeCup: Cup = {
width: 20,
height: 60,
};
let anmimalCup: Animal = coffeeCup;
就会抛出错误类型 "Cup" 中缺少属性 "name",但类型 "Animal" 中需要该属性。
类型断言的用途:
A
包含B
的所有属性,或者B
包含A
的所有属性,A
和B
才能相互断言双重断言意味着打破 「A
包含B
的所有属性,或者B
包含A
的所有属性,A
和B
才能相互断言」的规则,举个栗子:
interface Cat {
run(): void;
}
interface Fish {
siwm(): void;
}
function testCat(cat: Cat) {
return cat as any as Fish;
}
let tom: Cat = {
run() {
console.log("i can run");
},
};
testCat(tom);
声明全局变量
declare var username: string;
定义全局函数
declare function getToken(key: string): string