1.TypeScript是什么,与JavaScript的关系
ts是js的超集,是js更严格的严格版本。ts添加了静态类型系统和编译时的一些特性。
主要的联系和区别:
- 类型系统。js是动态类型的语言,不需要在代码中声明变量的类型;ts使用了静态类型系统,在代码中必须明确的声明所有变量的类型,这有利于发现错误,可使大型代码库更容易维护。
- 编译。ts需要经过编译才可以在浏览器或node中运行,它需要先转换成js代码在运行。
- 可扩展性。因为ts是js的超集,所以可以将现有的js项目迁移到ts,不需要重写整个代码。
- 类型安全。静态类型系统,可以使ts代码在编译阶段就可以发现错误,不需要等到运行时才发现。
- 高级类型。ts支持泛型、接口等,这可以使代码更加可维护。
2. TypeScript 中有哪些内置类型?
any
:表示任意类型,可以存储任何值。number
:表示数值类型,包括整数和浮点数。string
:表示字符串类型。boolean
:表示布尔类型,只有两个值:true 和 false。void
:表示无类型,通常用于表示没有返回值的函数。null
和undefined
:表示特殊的值类型。symbol
:表示唯一的标识符类型。tuple
:表示固定数量的元素集合,用于表示已知数量的不同类型的数据。enum
:表示枚举类型,用于定义一组命名的常量值。class
:表示类类型,用于定义对象和构造函数。interface
:表示接口类型,用于定义对象的形状和行为。type alias
:表示类型别名,用于为复杂类型定义简化的名称。function type
:表示函数类型,用于定义函数参数和返回值的类型。generic type
:表示泛型类型,用于定义可重用的组件,可以处理多种数据类型。
3. TypeScript中的接口是什么,如何使用?
接口在ts中用来定义对象的结构及属性的类型。使用interface定义
//定义接口 interface Person { name string; age number; eat(food string):string } //使用接口 class Student implements Person { name:string; age:number; constructor(name:string,age:number){ this.name = name; this.age = age; } eat(food:string){ return food; } }
4.TypeScript中如何定义和使用泛型?
泛型可以用来在定义函数、接口、类时不提前指定具体的类型,而是在使用的时候为其指定类型。
泛型有类型推断,编译器会根据传入的参数自动确定T的类型
function fn <T> (x:T,y:T): T{ return x + y; } fn<number>(1,2)
5.TypeScript中any和unknown类型的区别?
any类型表示任何值都可以,它会关闭编译器的类型检查,使用any类型,变量可以被赋值为任意类型。
unknown表示一个未知的值,比any更严格。使用unknown时不可以直接访问其内部属性,需要进行类型断言。这样可以增加类型安全性。
const x:unknown = new Person(); // x.name; 这种方法是错误的 const y = <any> x; //类型断言 x.name;
6.TypeScript中,枚举类型如何使用?
枚举类型:用于表示一组命名的常量值。
//定义枚举 enum Color { Red = 1, Blue = 2, Green = 3 } let bg:Color; bg = Color.Red; //获取枚举类型的key值 Object.keys(Color) Color[0]
7.在TypeScript中,什么是类型推断?
类型推断是编译器根据变量、函数的参数和返回值的实际使用情况推断出它们的类型。
8.在TypeScript中,什么是装饰器?
装饰器是一种特殊类型的声明,可以被附加到类声明、方法、属性或参数上。
如果要使用装饰器,需要在tsconfig.json中配置:
"compilerOptions": { "experimentalDecorators": true }
* 类装饰器(无法传参)
function fn1(target:any){ target.prototype.userName = '1' //添加属性 } @fn1 //相当于fn1(Person) class Person {} const p1 = new Person(); console.log(p1.userName); //1
* 装饰器工厂
function fn2(options:any){ return function (target:any){ target.prototype.name = options.name } } @fn2({ name:'jjjj' }) class Person1 {} const p2 = new Person1() console.log(p2.name);
如果有多个装饰器,会从上到下执行每个装饰器工厂,拿到所有真正的装饰器,然后从下到上执行所有的装饰器。
* 属性装饰器
function fn3(target:any,attr:any){ console.log(target,attr); //attr = undefined target[attr] = 'dd' console.log(target,attr); //attr = dd } class Person2 { @fn3 name:string }
* 方法装饰器
9.TypeScript中类型断言是什么?
类型断言类似于Java语言中的类型转换。类型断言对运行时没有影响,仅对编译器使用。
10. TypeScript中type和interface接口有什么区别?
- 接口只能定义对象类型,包括类、对象和对象的形状;类型别名可以表示任何类型。
- 接口可以被其他接口继承;类型别名不能直接继承,但可以通过交叉类型来组合多个类型,或者使用泛型来创建可重用的类型。
- 在不同地方声明相同名称的接口,会自动合并为一个接口;类型别名不可以重名。
11.TypeScript中const和readonly的区别是什么?
- const用来声明常量,一旦赋值就不可以被修改;readonly用来声明只读属性,该属性在初始化后就不可以被修改 。
- const声明的常量必须被初始化,类型在初始化时被固定,在声明后不可以修改;readonly可以在初始化时指定类型,但是可以在对象方法中被修改。
- const声明的变量有块级作用域;readonly声明的属性是对象的一部分,可以在对象方法中被访问。
- const在运行时检查;readonly在编译时检查。
12.TypeScript的tsconfig.json中有哪些配置信息?
- compilerOptions:编译器选项,如语言版本、目标JavaScript版本等;
- include:指定需要编译的文件路径或文件夹路径;
- exclude:指定不需要编译的文件路径或文件夹路径;
- files:指定需要编译的文件列表;
- extends:指定继承自另一个tsconfig.json文件;
- complieOnSave/buildOnSave:指定是否在保存时编译文件;
- target:编译目标JavaScript版本,如“ES5”、“ES6”;
- module:指定模块系统,可以是“CommonJS”、“AMD”等;
- outDir:编译输出的目录;
- strict:是否开启严格类型检查; .......
13.keyof和typeof关键字如何使用?
keyof:用于某个类型的所有属性名组成的联合类型,主要用在接口、对象或类的属性上。
interface Person { name:string; age:number; } type Keys = keyof Person; // 'name'|'age'
typeof:通常与类型联合使用,用来表示一个值的类型。用于获取一个值的类型。
14.TypeScript中的Declare关键字有什么作用?
declare用于声明一个变量、函数、类、模块等,但不为其分配具体的实现。通常用于告诉ts编译器某个变量、函数存在于代码之外,可能在一个外部的库中,或运行环境中。通过使用declare,可以在ts代码中安全的使用这些外部的实体,而不会引发编译错误。
15. TypeScript 模块的加载机制?
TypeScript的模块加载机制基于nodejs的模块加载机制,采用相对路径和绝对路径来查找。
ts会按照一定的顺序在文件系统路径中查找,如果找不到模块,ts会尝试在全局安装的模块中查找该模块,最后找不到,会抛出错误。
16.如何理解TypeScript中的类型兼容性?
ts中的类型兼容性是指一个类型是否可以被赋值给另一个类型。类型兼容性是基于结构类型系统来判断的,如果一个类型结构上包含另一个类型的所有信息,那这个类型就可以赋值给另一个类型。
interface Person { name:string; age:number; } class Student implements Person { name = 'a'; age = 18; say:():void => {} } const s1:Person = {name:'b',age:10} cinst s2:Person = new Student() //虽然Student比Person属性更多,但是Student中包含了Person中的所有属性。所以Student兼容于Person。
17.TypeScript 中对象展开会有什么副作用吗?
- 深拷贝问题,对象展开是浅拷贝,如果对象的属性值为对象或数组,展开运算符只会复制顶层的引用地址,如果修改可能会修改原对象。
- 类型推断,如果一个对象属性没有明确的类型注解,ts可能无法推断出该属性的类型,这就需要额外的类型注解或类型断言。
- 性能开销,对于大型的对象,对象展开可能会导致额外的性能开销。
- 可读性和可维护性,可能会降低代码的可读性和可维护性。
18.Omit 类型有什么作用?怎么使用?
Omit是一个泛型类型,用于从一个给定的类型中排除某些属性,并返回一个新的类型。
type Person = {name:string; age:number; gender:string} type WithoutGender = Omit<Person,'gender'> //{name:string; age:number; }
......持续更新中