泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function createArray(length: number, value: T): Array {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
上例中,我们在函数名后添加了
接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来
多个类型参数
//类型推断 T为number U为string
function swap(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
swap([7, 'seven']); // ['seven', 7]
泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:
function loggingIdentity(arg: T): T {
console.log(arg.length);
return arg;
}
// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.
上例中,泛型 T 不一定包含属性 length,所以编译的时候报错了。这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:
interface Lengthwise {
length: number;
}
function loggingIdentity(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity('hello world'); //string 类型是有length属性的 如果传数字类型 则编译仍然会报错
泛型接口
interface CreateArrayFunc {
(length: number, value: T): Array;
}
let createArray: CreateArrayFunc;
//这里需要传递参数的
//如果是下面这种形式,则声明变量时不需要传递参数
interface CreateArrayFunc {
(length: number, value: T): Array;
}
let createArray: CreateArrayFunc;
createArray = function(length: number, value: T): Array {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
createArray(3, 'x'); // ['x', 'x', 'x']
泛型类
class GenericNumber {
//还可以指定默认值
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
类型断言
类型断言可以用来手动指定一个值的类型,即允许变量从一种类型更改为另一种类型。
格式:<类型>值 或值 as 类型
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即 值 as 类型
。
形如
的语法在 tsx 中表示的是一个 ReactNode
,在 ts 中除了表示类型断言之外,也可能是表示一个泛型。故建议大家在使用类型断言时,统一使用 值 as 类型
这样的语法
类型断言只能够欺骗TypeScript 编译器,无法避免运行时的错误。
使用场景
- 将一个联合类型断言为其中一个类型,如:
interface Cat {
name: string;
run(): void;
}
interface Fish {
name: string;
swim(): void;
}
function isFish(animal: Cat | Fish) {
if (typeof (animal as Fish).swim === 'function') {
return true;
}
return false;
}
- 将一个父类断言为更加具体的子类,比如:
interface ApiError extends Error {
code: number;
}
interface HttpError extends Error {
statusCode: number;
}
function isApiError(error: Error) {
if (typeof (error as ApiError).code === 'number') {
return true;
}
return false;
}
- 将任何一个类型断言为 any 比如:(window as any).foo = 1;
- 将 any 断言为一个具体的类型 比如:
function getCacheData(key: string): any {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData('tom') as Cat; //断言为 Cat 类型
tom.run();
要使得 A 能够被断言为 B,只需要 A 兼容 B 或 B 兼容 A 即可
双重断言:任何类型都可以被断言为 any,any 可以被断言为任何类型。如:
interface Cat {
run(): void;
}
interface Fish {
swim(): void;
}
//Cat 断言为any类型,any类型断言为具体类型 Fish
//语法上没有错误,可能会出现运行错误,请谨慎使用。
function testCat(cat: Cat) {
return (cat as any as Fish);
}
类型断言和类型转换
类型断言只会影响 TypeScript 编译时的类型,类型断言语句在编译结果中会被删除,所以类型断言不是类型转换,它不会真的影响到变量的类型
类型断言和类型声明
类型声明比类型断言更加严格,类型断言,只要A、B有兼容即可用,但是类型声明则更加严格。
类型断言和泛型
function getCacheData(key: string): T {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData('tom');
tom.run();
声明文件
通常我们会把声明语句放到一个单独的文件中,这就是声明文件,声明文件必需以 .d.ts 为后缀。
内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。
ECMAScript 标准提供的内置对象有:Boolean、Error、Date、RegExp 等。
DOM 和 BOM 提供的内置对象有:Document、HTMLElement、Event、NodeList 等。
如:
let b: Boolean = new Boolean(1);
let e: Error = new Error('Error occurred');
let d: Date = new Date();
let r: RegExp = /[a-z]/;
let body: HTMLElement = document.body;
let allDiv: NodeList = document.querySelectorAll('div');
document.addEventListener('click', function(e: MouseEvent) {
// Do something
});
声明合并:http://ts.xcatliu.com/advanced/declaration-merging.html