当前位置: 首页 > news >正文

cocos creator学习之typeScript常见语法问题

1. TypeScript 和 JavaScript 的区别是什么?

(1) 类型检查时机不同

TypeScript 编译时(代码编写后、运行前),JavaScript 运行时(代码执行到对应语句时)

TypeScript:编译时直接报错,提前拦截问题

function add(a: number, b: number) {return a + b;
}
// 报错: Argument of type 'string' is not assignable to parameter of type 'number'
add(1, "2"); 

JavaScript:运行时才报错,若未执行到该代码则不会发现问题

function add(a, b) {return a + b;
}
// 运行时不报错,但返回非预期结果 "12"(字符串拼接)
console.log(add(1, "2")); 
// 若调用时参数类型错误且未执行,代码无任何提示

(2)类型的声明方式

TypeScript         支持显式声明(如 let a: number = 1),也支持自动类型推断

JavaScript        无显式声明,变量类型随赋值动态变化

  (3) 语法特性差异:TypeScript 新增核心能力

TypeScript 在 JavaScript 语法基础上,新增了一系列围绕 “类型” 的特性,这些特性在 JavaScript 中完全不存在。

---  枚举(Enum) 定义一组命名的常量,提高代码可读性和可维护性(JavaScript 需通过对象模拟)。

// 数字枚举(默认从 0 开始递增)
enum Direction {Up,    // 0Down,  // 1Left,  // 2Right  // 3
}// 字符串枚举
enum Status {Pending = "PENDING",Success = "SUCCESS",Error = "ERROR"
}const currentStatus: Status = Status.Success;

--- 元组 (Tuple)

 限定数组的长度和每个元素的类型(JavaScript 数组元素类型可任意混合)。

// 元组:第一个元素为 string,第二个为 number
let user: [string, number] = ["Bob", 30];
user = [123, "Alice"]; // 报错:类型不匹配

---  接口(Interface) 定义对象的结构契约,强制实现者遵循约定的属性和方法(JavaScript 无接口概念,需通过注释或逻辑约束)。

--- 类型别名(Type)为任意类型定义别名,简化复杂类型的复用。

// 为基础类型定义别名
type Age = number;
let userAge: Age = 28;// 为联合类型定义别名
type StringOrNumber = string | number;
let value: StringOrNumber = "test";
value = 123; // 合法// 为对象类型定义别名
type Point = { x: number; y: number };
const p: Point = { x: 10, y: 20 };

--- 泛型语法的支持, 实现类型的 “参数化”,创建可复用的组件(如函数、类),适配多种类型(JavaScript 需通过 any 牺牲类型安全)。

// 泛型函数:返回与输入相同类型的值
function identity<T>(arg: T): T {return arg;
}const num: number = identity(42);
const str: string = identity("hello");// 泛型类
class Container<T> {private value: T;constructor(value: T) {this.value = value;}getValue(): T {return this.value;}
}const stringContainer = new Container("test");

--- 高级类型操作, 联合类型(Union Types),交叉类型(Intersection Types),映射类型(Mapped Types)

2. 接口(interface)和类型别名(type)的区别?

在 TypeScript 中,interface(接口)和 type(类型别名)都可以用来定义复杂类型,但它们在功能、使用场景和行为上存在一些关键区别。

(1) 基本语法定义

interface:专门用于定义对象的结构,使用 interface 关键字。

interface User {name: string;age: number;
}

type:可以为任意类型(包括基本类型、联合类型、交叉类型等)定义别名,使用 type 关键字。

// 为对象类型定义别名
type User = {name: string;age: number;
};// 为基本类型定义别名
type Age = number;// 为联合类型定义别名
type Status = "pending" | "success" | "error";

(2)扩展(继承)能力

interface:支持通过 extends 关键字扩展其他接口或类型,实现继承。

interface Person {name: string;
}// 扩展 Person 接口
interface User extends Person {age: number;
}const user: User = {name: "Alice",age: 30 // 必须包含扩展的属性
};

type:不支持 extends,但可以通过交叉类型(&)实现类似扩展的效果。

type Person = {name: string;
};// 通过交叉类型扩展
type User = Person & {age: number;
};const user: User = {name: "Bob",age: 25
};

(3) 合并声明(声明合并)

interface:支持声明合并,即多次定义同名接口会自动合并属性。

// 第一次定义
interface User {name: string;
}// 第二次定义,会与第一次合并
interface User {age: number;
}// 合并后:{ name: string; age: number }
const user: User = {name: "Charlie",age: 35
};

type:不支持声明合并,同名的 type 会报错。

type User = { name: string };
type User = { age: number }; // 报错:标识符“User”重复

interface 不能定义基本类型的别名,而 type 可以:

type Age = number; // 合法
interface Age = number; // 报错:语法错误

3. 如何定义可选属性?

使用 ? 标记可选属性。

interface Person {name: string;age?: number; // 可选
}const p: Person = { name: "Alice" }; // 合法type Student = {name: string,age?: number   //可选
}

4. 类型守卫(Type Guard)是什么?如何实现?

使用 typeof 或自定义谓词函数。

function isNumber(x: any): x is number {return typeof x === "number";
}function processValue(value: number | string): void {if (isNumber(value)) {console.log(value.toFixed(2));} else {console.log(value.toUpperCase());}
}

5. any 和 unknown 的区别?

在 TypeScript 中,any 和 unknown 都用于表示 “类型不确定” 的值,但它们的类型安全性有本质区别,这直接影响了代码的健壮性。

核心区别:类型检查的严格程度

any:完全关闭类型检查,允许对其执行任何操作,不进行任何类型验证。

unknown:开启严格类型检查,必须先确认类型后才能执行操作,是 “类型安全的 any”。

--- any:可以对 any 类型的值执行任何操作(调用方法、访问属性等),TypeScript 不会报错。

let value: any = "hello";
value.toUpperCase(); // 允许(正确操作)
value.foo(); // 允许(即使 foo 方法不存在,也不报错)
value = 42;
value.toFixed(2); // 允许
value = true;
value.toExponential(); // 允许(编译时不报错,运行时可能出错)

--- unknown:不能直接对 unknown 类型的值执行操作,必须先通过类型检查确认其具体类型。

let value: unknown = "hello";
value.toUpperCase(); // 报错:对象的类型为 "unknown"// 必须先做类型判断
if (typeof value === "string") {value.toUpperCase(); // 允许(此时 TypeScript 知道是 string 类型)
}value = 42;
value.toFixed(2); // 报错:对象的类型为 "unknown"
if (typeof value === "number") {value.toFixed(2); // 允许
}

6. 装饰器(Decorator)是什么?如何使用?

TypeScript 中的装饰器(Decorator)是一种特殊类型的声明,它能够修改类、方法、属性或参数的行为。装饰器基于 JavaScript 的元编程(MetaProgramming)特性,允许在不修改原有代码结构的前提下,为代码添加额外功能(如日志记录、性能统计、权限校验等)。

装饰器目前是 TypeScript 的实验性特性,需要在 tsconfig.json 中启用配置才能使用:

{"compilerOptions": {"target": "ES5","experimentalDecorators": true,  // 启用装饰器"emitDecoratorMetadata": true    // 可选,生成装饰器元数据}
}

装饰器按作用目标可分为类装饰器、方法装饰器、属性装饰器、参数装饰器,它们的语法都是在目标前加上 @装饰器名称

(1)类装饰器(Class Decorators)

作用于类本身,用于修改类的行为(如添加方法、修改构造函数等)。

语法:接收一个参数(类的构造函数),返回值可以是新的构造函数(用于替换原类)。

// 定义类装饰器:为类添加静态属性和实例方法
function addMetadata(constructor: Function) {// 添加静态属性constructor.prototype.version = "1.0.0";// 添加实例方法constructor.prototype.log = function() {console.log(`Class name: ${this.constructor.name}`);};
}// 应用装饰器
@addMetadata
class User {name: string;constructor(name: string) {this.name = name;}
}// 使用装饰器添加的功能
const user = new User("Alice");
console.log(user.version); // 1.0.0(装饰器添加的属性)
user.log(); // Class name: User(装饰器添加的方法)

(2)方法装饰器(Method Decorators)

作用于类的方法,用于修改方法的行为(如添加日志、缓存结果、权限校验等)。

语法:接收三个参数:

  • target:对于静态方法是类本身,对于实例方法是类的原型对象
  • propertyKey:方法名称
  • descriptor:方法的属性描述符(包含 valuewritable 等)
// 定义方法装饰器:打印方法调用日志
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {// 保存原方法const originalMethod = descriptor.value;// 重写方法descriptor.value = function(...args: any[]) {console.log(`调用方法 ${propertyKey},参数:`, args);const result = originalMethod.apply(this, args); // 执行原方法console.log(`方法 ${propertyKey} 返回值:`, result);return result;};return descriptor;
}class Calculator {// 应用方法装饰器@logMethodadd(a: number, b: number): number {return a + b;}
}const calc = new Calculator();
calc.add(2, 3); 
// 输出:
// 调用方法 add,参数: [2, 3]
// 方法 add 返回值: 5

(3)属性装饰器(Property Decorators)

作用于类的属性,用于修改属性的行为(如添加默认值、验证规则等)。

语法:接收两个参数(与方法装饰器前两个参数相同),返回值会被忽略。

// 定义属性装饰器:为属性设置默认值
function defaultValue(value: any) {return function(target: any, propertyKey: string) {target[propertyKey] = value; // 设置默认值};
}class Person {// 应用属性装饰器@defaultValue("Unknown")name: string;@defaultValue(18)age: number;
}const person = new Person();
console.log(person.name); // Unknown(装饰器设置的默认值)
console.log(person.age);  // 18(装饰器设置的默认值)

7. 可索引类型(Indexable Types)

TypeScript 的可索引类型(Indexable Types) 用于描述那些可以通过索引访问的对象(如数组、对象字面量),它定义了通过索引(如数字索引、字符串索引)访问时返回值的类型。

可索引类型的核心是索引签名(Index Signature),通过它可以约束:

  • 索引的类型(只能是 string 或 number
  • 通过索引访问返回值的类型

(1)字符串索引签名(最常用)

用于描述通过字符串索引访问的对象(如普通对象),表示当使用字符串作为索引时,返回值的类型。

// 定义一个具有字符串索引签名的接口
interface StringMap {// 字符串索引签名:key 是 string 类型,返回值是 number 类型[key: string]: number;
}// 符合接口的对象
const counts: StringMap = {apple: 5,banana: 10,// "orange": "many"  // 报错:返回值必须是 number 类型
};// 通过字符串索引访问
console.log(counts["apple"]); // 5(类型为 number)
console.log(counts.banana);   // 10(类型为 number)

(2) 数字索引签名

用于描述通过数字索引访问的对象(如数组),表示当使用数字作为索引时,返回值的类型。

// 定义一个具有数字索引签名的接口
interface NumberArray {// 数字索引签名:index 是 number 类型,返回值是 string 类型[index: number]: string;
}// 符合接口的数组
const fruits: NumberArray = ["apple", "banana", "cherry"];// 通过数字索引访问
console.log(fruits[0]); // "apple"(类型为 string)
console.log(fruits[1]); // "banana"(类型为 string)

(3)用类型别名定义可索引类型

除了接口,也可以用 type 定义可索引类型:

type NumberMap = {[key: string]: number;
};type StringArray = {[index: number]: string;
};

8. 如何使用 never 类型?

在 TypeScript 中,never 类型表示永远不会发生的值的类型。它描述的是那些根本不可能存在的状态,通常用于表示函数不会正常返回、变量永远不会被赋值等场景。

---  never 是所有类型的子类型,可以赋值给任何类型

--- 没有任何类型是 never 的子类型(除了 never 本身),因此不能将其他类型赋值给 never 类型的变量

(1) 永不返回的函数(终止函数)

当函数抛出异常或进入无限循环(永远不会执行完)时,其返回值类型为 never

// 抛出异常的函数
function throwError(message: string): never {throw new Error(message); // 函数不会正常返回
}// 无限循环的函数
function infiniteLoop(): never {while (true) {// 循环永远不会结束}
}

这类函数无法被正常执行完毕,因此 TypeScript 推断其返回类型为 never 而非 voidvoid 表示函数正常执行完毕但没有返回值)。

(2) 表示不可能被赋值的变量

如果变量的类型是 never,则它永远不能被赋值(除了 never 本身)。

let impossible: never;impossible = 123; // 报错:不能将 number 类型赋值给 never 类型
impossible = "hello"; // 报错:不能将 string 类型赋值给 never 类型
impossible = throwError("出错了"); // 合法:throwError 返回 never 类型

http://www.dtcms.com/a/491838.html

相关文章:

  • 公司网站突然打不开了品牌网站建设 蝌蚪6小
  • 网站 没有备案 访问不了工商联网站建设方案
  • 存在即合理?数字化转型需破除“流程惯性“思维、重构底层逻辑
  • 南阳企业网站制作做网站推广和网络推广
  • 专业网站建站费用wordpress当前网址参数
  • 天猫网站是用什么技术做的东莞响应式网站哪家强
  • 茶文化网站建设内容网络管理软件免费
  • RocketMQ基础知识
  • 天气预报:基于python天气分析预测系统 气象数据分析 机器学习 爬虫 多元线性回归预测算法 中国天气网 Flask框架(建议收藏)✅
  • React 18 的核心设计理念:并发渲染
  • 昆明 网站建设兼职北京石景山网站建设
  • 中小型网站建设资讯网站及数据库怎么做后门
  • 建设网站财务分析wordpress中修改链接
  • 网站模板 实验室西安国际网站设计
  • 建设实验室网站的意义湖南长沙房价
  • 行业热点丨仿真驱动设计:兼顾性能、可持续性与效益
  • 番禺建设网站策划南充房产管理网
  • 网站建设xywlcn网站云主机
  • 网站建设静态部分报告总结长沙旅游必去的八个景点
  • 5种方法解决:安装一个或多个角色、角色服务或功能失败。找不到源文件
  • 虚幻引擎5 GAS开发俯视角RPG游戏 P05-11 消息小部件
  • 网站seo综合诊断福田服务商app软件安装
  • 无缝开发通道:IT-Tools+CPolar让远程协作像坐在一起编码
  • 网站普查建设背景网页qq属于
  • 网站建设 局部放大镜功能wordpress建英文网站
  • 武冈网站建设怎么买网站空间
  • 从0开始掌握企业知识库构建:核心概念与实践入门
  • 伦教网站设计宣传广告牌图片
  • 文案撰写网站wordpress登录密码错误
  • NewStarCTF2025-Week1-Misc