Ts:类型断言,泛型

本文详细介绍了TypeScript中类型断言的使用,包括父类到子类、子类到父类的断言,以及如何利用类型断言避免类型检查错误。此外,还探讨了类型断言与类型声明的区别,并通过示例展示了泛型在函数、接口和类中的应用,强调了泛型在类型安全和代码复用上的优势。最后,对比了类型断言和泛型的使用场景,指出泛型是更为规范和安全的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
<think>嗯,用户想了解TypeScript类型断言的使用场景,还特别要求提供实际例子。从问题看,用户可能是个正在学习TypeScript的前端开发者,遇到了需要手动指定类型的情况。这类问题通常出现在处理第三方库或动态数据时,用户需要知道什么时候该"告诉编译器我知道这是什么类型"。之前提供的引用材料很有价值。引用[1]明确了类型断言是开发者主动告诉编译器类型的行为,引用[3]则详细列出了适用场景。用户显然不需要基础语法解释,而是要解决实际编码中的类型困惑。值得注意的难点是区分类型断言类型转换。用户可能混淆这两者,需要强调断言只在编译阶段起作用。另外安全边界也很重要,比如asany的危险性应该特别提醒。示例选择上应该覆盖典场景:DOM操作(基本但高频)、联合类型窄化(实用技巧)、约束(高级用法)、JSON解析(实际痛点)。每个例子都要让用户感受到"啊这正是我遇到的麻烦"。特别要突出React的示例,因为现在很多TS用户都在用React。用户没问但可能想知道的是类型守卫和断言的配合使用,这个可以放在注意事项里作为延伸。最后要提醒eslint规则,很多人会忽略静态检查的重要性。</think> 以下是关于 TypeScript 类型断言的详细解析及典使用场景: ### 一、类型断言核心概念 1. **本质** 开发者**主动告知编译器变量类型**的机制(非类型转换),通过断言可跳过 TS类型检查(`as` 或 `<Type>` 语法) 2. **与类型推论区别** ![类型断言 vs 类型推论](https://via.placeholder.com/400x150?text=TypeScript+类型系统) 如引用[2]所示: ```typescript let str = "Hello"; // 类型推论为 string ✅ str = 10; // Error ❌ ``` --- ### 二、核心使用场景及代码示例 #### 场景 1:操作 DOM 元素 ```typescript // TS 无法推断具体元素类型 const canvas = document.getElementById('myCanvas') as HTMLCanvasElement; const ctx = canvas.getContext('2d'); // 正确识别 canvas API ✅ ``` #### 场景 2:联合类型窄化 ```typescript interface Fish { swim(): void } interface Bird { fly(): void } function move(pet: Fish | Bird) { // 断言后访问特定方法 if ((pet as Fish).swim) { (pet as Fish).swim(); } } ``` #### 场景 3:约束特定类型 ```typescript function convert<T>(input: any): T { return input as T; // 明确指定返回类型 } const data = convert<string>(apiResponse); // => string 类型 ``` #### 场景 4:跨系统数据兼容 ```typescript // 处理非TS系统的API返回 const apiData = { id: 1, name: "TS" } as unknown as ApiResponse; ``` --- ### 三、最佳实践要点 1. **优先类型守卫** ```typescript if (typeof input === 'string') { /*...*/ } // 比断言更安全 ``` 2. **避免双重断言** ❌ `obj as any as Data` (除非必要) 3. **React 特殊场景** ```tsx const fileInput = useRef<HTMLInputElement>(null); // 组件挂载后断言 useEffect(() => { (fileInput.current as HTMLInputElement).click() }, []) ``` > ⚠️ **注意事项** > - 断言不会运行时类型验证(可能引发运行时错误) > - 优先使用类型守卫或函数重载替代 > - 禁用 `as any`(会完全破坏类型系统) --- ### 四、典错误案例 ```typescript // 错误断言导致运行时崩溃 const num: string = "123"; const value = (num as unknown as number) + 100; // 实际运行时 NaN ``` --- **相关问题** 1. 类型断言类型转换(Type Conversion)有何本质区别? 2. 如何处理 `as` 断言时的 ESlint 报错 (`@typescript-eslint/no-unsafe-cast`)? 3. 类型断言在 React Hooks(如 `useRef`)中的具体应用场景? > 引用来源: > [1] TypeScript 类型断言原理与场景. TS 官方文档扩展 > [2] TypeScript Deep Dive. 类型系统章节 > [3] React with TypeScript Best Practices. Frontend Masters 2023
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值