Ts:断言
类型断言兼容
interface Animal {
name: string;
}
interface Cat {
name: string;
run(): void;
}
function testAnimal(animal: Animal) {
return (animal as Cat);
}
function testCat(cat: Cat) {
return (cat as Animal);
}
- 允许 animal as Cat 是因为「父类可以被断言为子类」,就是父类接口类型可以具体为子类。
- 允许 cat as Animal 是因为既然子类拥有父类的属性和方法,那么被断言为父类,获取父类的属性、调用父类的方法,就不会有任何问题,故「子类可以被断言为父类」,因为子类继承自父类,所以父类的属性方法,子类都可以访问,即具体的子类可以断言为父类
将任何一个类型断言为 any,规避ts校验错误
window.foo = 1; // 临时添加属性,报错,window上没有该属性
(window as any).foo = 1; // 在 any 类型的变量上,访问任何属性都是允许的。它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any
将 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();
类型断言 vs 类型声明
interface Animal {
name: string;
}
interface Cat {
name: string;
run(): void;
}
const animal: Animal = {
name: 'tom'
};
// 类型断言
let tom = animal as Cat; // 正确
------------------------------------
// 类型声明
let tom: Cat = animal; // 报错
它们的核心区别就在于:
- animal 断言为 Cat,只需要满足 Animal 兼容 Cat 或 Cat 兼容 Animal 即可,即父类断言为具体的子类。
- animal 赋值给 tom,tom为cat类型,animal为Animal类型,相当于Annimal类型赋值给Cat类型的话,明显是不能赋值的,结构有缺陷。cat的接口类型更具体,所以范围比animal小,所以是animal兼容了cat
总结就是animal接口包住了cat,cat在animal的基础上扩展了方法,所以cat结构可以声明给animal
类型断言 vs 泛型
通过给 getCacheData 函数添加了一个泛型 ,我们可以更加规范的实现对 getCacheData 返回值的约束,这也同时去除掉了代码中的 any,是最优的一个解决方案。
function getCacheData<T>(key: string): T {
return (window as any).cache[key];
}
interface Cat {
name: string;
run(): void;
}
const tom = getCacheData<Cat>('tom');
tom.run();
泛型 :
*泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性*
// 无返回值
function fn4<T>(a: T) {
console.log(a);
}
fn4(5); // 不指定泛型,自动推论
fn4<string>('23'); // 指定泛型
// 有返回值
function fn5<T>(a: T): T {
console.log(a);
return a;
}
泛型--------------多个参数
function fn6<T, K>(a: T, b: K) {
console.log(a, b);
}
fn6<number, string>(10, '12');
泛型约束,泛型继承接口 ,泛型要满足接口形状
interface inter {
length: number
}
function fn7<T extends inter>(a: T) {
// a的类型来自T,T来自inter
console.log(a.length);
}
泛型接口,定义函数的形状:
interface IG {
<T>(length: number, arg: T): T;
}
let fn: IG = function <T>(length: number, arg: T): T {
return arg;
// return arg + '';
}
泛型类
class CS<T> {
constructor(public attr: T) { };
zeroValue: T;
fn(): T {
return this.attr;
}
// 静态成员不能使用泛型类型
// static a: T = ''; // Error
}
// 实例化时传入类型值
const cs = new CS<number>(123);
cs.fn(); // 123