Typescript面试题

interface 和 type 的区别

1.定义和用途:

  • interface:interface被用作定义对象的类型,它描述了一个对象应有的形状(即属性和方法)。
interface Person {  
  firstName: string;  
  lastName: string;  
  age?: number; // 可选属性  
  fullName(): string; // 方法  
}  
  • type:除了对象类型,type还可以定义联合类型、交叉类型、元组等,并支持更高级的类型操作。
type Name = string;  
// 函数声明
type NameResolver = () => string;  
type NameOrResolver = Name | NameResolver; 
// 元组
type Tuple = [string, number];  
const myTuple: Tuple = ['hello', 123];
// 映射类型
type Keys = 'a' | 'b' | 'c';  
type Obj = { [K in Keys]: string }; // { a: string; b: string; c: string; }

2.可扩展性:

  • interface 是可以扩展的,你可以使用 extends 关键字来扩展一个 interface
interface Animal {  
  name: string;  
}  
  
interface Mammal extends Animal {  
  milk: boolean;  
}
  • type 通过交叉类型 (&) 来实现类似的功能。
type Animal = {  
  name: string;  
};  
  
type Mammal = Animal & { milk: boolean };

3.声明合并:

  • interface 可以声明合并,即如果多个 interface 定义了相同的名称,它们会被合并成一个。
interface User {  
  id: number;  
}  
  
interface User {  
  name: string;  
}  
  
const user: User = {  
  id: 1,  
  name: 'John'  
};
  • type 不支持声明合并。

TypeScript 泛型

TypeScript 中的泛型(Generics)是一种在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。泛型的主要目的是在定义组件时,创建可重用的代码,这些代码可以支持多种数据类型,从而提高了代码的复用性和灵活性。

泛型函数
泛型函数是在定义时不指定参数类型,而在调用时传入类型参数。类型参数用尖括号 <> 包围,并放在函数名后面。

function identity<T>(arg: T): T {  
    return arg;  
}  
  
let output = identity<string>("myString");  // 输出: "myString"  
let numOutput = identity<number>(123);     // 输出: 123

在这个例子中,T 是一个类型变量,表示任意类型。当我们调用 identity 函数时,可以传入任意类型的参数,并在返回值时保持相同的类型。

泛型类
泛型类是在类定义中引入类型参数。

class GenericNumber<T> {  
    zeroValue: T;  
    add: (x: T, y: T) => T;  
}  
  
let myGenericNumber = new GenericNumber<number>();  
myGenericNumber.zeroValue = 0;  
myGenericNumber.add = function(x, y) { return x + y; };  
  
console.log(myGenericNumber.add(10, 20));  // 输出: 30

在这个例子中,GenericNumber 类有一个类型参数 T,可以用来定义 zeroValue 属性和 add 方法的类型。

泛型接口
泛型接口允许我们定义接口时,不预先指定具体的类型,而是在实现接口的时候指定。

interface GenericIdentityFn<T> {  
    (arg: T): T;  
}  
  
function identity<T>(arg: T): T {  
    return arg;  
}  
  
let myIdentity: GenericIdentityFn<number> = identity;

在这个例子中,GenericIdentityFn 是一个泛型接口,它描述了一个接受类型 T 的参数并返回相同类型 T 结果的函数类型。然后我们使用这个函数类型去描述 identity 函数。

泛型约束
有时候我们可能希望泛型类型 T 必须满足一定的条件。这时候,我们可以使用接口来定义约束。

interface Lengthwise {  
    length: number;  
}  
  
function loggingIdentity<T extends Lengthwise>(arg: T): T {  
    console.log(arg.length);  // 因为 T 是 Lengthwise 的子类,所以可以访问 length 属性  
    return arg;  
}  
  
loggingIdentity({length: 10, value: 3});  // 输出: 10

在这个例子中,我们定义了一个 Lengthwise 接口,它有一个 length 属性。然后,我们定义了一个泛型函数 loggingIdentity,它的类型参数 T 必须满足 Lengthwise 接口的约束。

TypeScript中 Any 和 UNKnown

any 类型在 TypeScript 中表示可以是任意类型的值。当你不知道一个变量的确切类型,或者你想跳过类型检查时,你可以使用 any 类型。使用 any 类型可以绕过 TypeScript 的类型系统,但这通常不是一种好的做法,因为它会失去类型安全的优势

let variable: any;  
variable = "Hello";  
variable = 123;  
variable = true;

unknown 类型是 TypeScript 3.0 中引入的一个新类型,它表示一个值可以是任意类型,但你不能直接对该值进行任何操作,除了赋值给另一个 unknown 类型的变量、赋值给 any 类型的变量、或者进行类型断言或类型守卫。这有助于在编译时捕获可能的类型错误。

let value: unknown;  
  
value = "Hello";  
// value.toUpperCase(); // 错误!不能直接调用方法,因为 value 的类型是 unknown  
  
if (typeof value === "string") {  
  console.log(value.toUpperCase()); // 正确!在类型守卫之后,我们知道 value 是字符串  
}

总结

  • any 类型用于当你不知道或不想指定一个变量的类型时。它绕过了类型检查,通常不推荐使用,因为它会失去 TypeScript 的类型安全优势。
  • unknown 类型用于当你希望保留对变量值的类型不确定性,同时仍然能够在编译时捕获可能的类型错误时。它强制你进行显式的类型检查或类型断言,以确保对变量的操作是类型安全的。

在编写 TypeScript 代码时,通常建议使用 unknown 类型而不是 any 类型,以保留类型安全性。当你确实需要绕过类型检查时,可以使用 any 类型,但要谨慎使用,并尽量避免在大型代码库中使用它。

使用ts写一个对象属性约束

使用{useName:string, password:number}约束传入的userData参数(并将password置为可选参数)

class User{
    useName:string;
    password?:number|undefined;
    //使用{useName:string, password?:number|undefined}约束传入的userData参数
    constructor(userData:{useName:string, password?:number|undefined}){
        this.useName=userData.useName;
        if(userData.password)
        this.password=userData.password;
    }
}

let u1=new User( {useName:"小猪猪", password:12233} );
let u2=new User( {useName:"大猪猪"} )

console.log(u1); 
console.log(u2);

说一下typescript中的泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

通俗理解:泛型就是解决类 接口 方法的复用性、以及对不特定数据类型的支持

function getData(value:string):string{
  return value //只能返回string类型的数据
}

//想要同时返回string和number类型
//1.通常: 代码冗余
function getData1(value:string):string{
  return value
}
function getData2(value:number):number{
  return value
}
//2.用any(可以解决,但是放弃了类型检查)
function getData(value:any):any{
  return value //什么类型都可以
}
//传入什么返回什么。比如传入number类型,必须返回number类型。传入string必须返回string类型。用any就可以不一致。

//泛型,可以支持不特定的数据类型
//要求:传入参数和返回的参数一致
//这里的T指泛型,也可以用任意字母取代,但是前后要一致
function getData<T>(value:T):T{
  return value
}
function getData<T>(value:T):T{
  return 'xxxx' //错误写法。不能将任何任性分配给T
}
//调用
getData<number>(123); //123 
getData<number>('xxx'); //错误写法

//可以调用的时候传一个泛型,返回的时候返回其他的类型(用的不多)
function getData<T>(value:T):any{
  return 'xxx'
}
//调用 
getData<number>(123); //xxx
getData<string>('xxx'); //xxx
//定义泛型是什么类型,就要传入什么类型的参数

如何在TS中对函数的返回值进行类型约束

ts中函数参数的类型定义

函数的参数可能是一个,也可能是多个,有可能是一个变量,一个对象,一个函数,一个数组等等。

1.函数的参数为单个或多个单一变量的类型定义

function fntA(one, two, three) {
	// 参数 "two" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型。
    return one + two + three
}
const aResult = fntA(1, '3', true)

修改后:

function fntA(one: number, two: string, three: boolean) {
    return one + two + three
}
const aResult1 = fntA(1, '3', true)
// 如果函数的参数为单个或者多个变量的时候,只需要为这些参数进行静态类型下的基础类型定义就行

2.函数的参数为数组的类型定义

function fntB(arr) {
	//参数 "arr" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型。
    return arr[0]
}
const bResult = fntB([1, 3, 5])

修改后:

function fntB(arr: number[]) {
    return arr[0]
}
const bResult1 = fntB([1, 3, 5])
// 如果参数是数组时,只需要为这些变量进行对象类型下的数组类型定义

3.函数的参数为对象的类型定义

function fntC({ one, two }) {
    return one + two
}
const cResult = fntC({ one: 6, two: 10 })

修改后:

function fntC({ one, two }: { one: number, two: number }) {
    return one + two
}
const cResult1 = fntC({ one: 6, two: 10 })
// 如果参数是对象,只需要为这些变量进行对象类型下的对象类型定义

4.函数的参数为函数的类型定义

function fntD(callback) {
	//参数 "callback" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型
    callback(true)
}
function callback(bl: boolean): boolean {
    console.log(bl)
    return bl
}
const dResult = fntD(callback)

修改后:

function fntD(callback: (bl: boolean) => boolean) {
    callback(true)
}
function callback(bl: boolean): boolean {
    console.log(bl)
    return bl
}
const dResult = fntD(callback)
// 如果参数是函数,只需要为参数进行对象类型下的函数类型定义即可

ts中函数返回值的类型定义

当函数有返回值时,根据返回值的类型在相应的函数位置进行静态类型定义即可

返回数字:

function getTotal2(one: number, two: number): number {
    return one + two;
}
const total2 = getTotal(1, 2);
// 返回值为数字类型

返回布尔值

function getTotal2(one: number, two: number): boolean {
    return Boolean(one + two);
}
const total2 = getTotal(1, 2);
// 返回值为布尔类型

返回字符串

function getTotal2(one: string, two: string): string{
    return Bone + two;
}
const total2 = getTotal('1', '2');
// 返回值为字符串

返回对象

function getObj(name: string, age: number): { name: string, age: number } {
    return {name,age}
}
getObj('小红',16)
// 返回值为对象

返回数组

function getArr(arr: number[]) :number[]{
    let newArr = [...arr]
    return newArr
}
getArr([1,2,3,4])
// 返回值为数组

函数返回值为underfinde,仅仅时为了在内部实现某个功能,我们就可以给他一个类型注解void,代表没有任何返回值,

function sayName() {
    console.log('hello,world')
}

修改后:

function sayName1(): void {
    console.log('无返回值')
}

当函数没有返回值时

// 因为总是抛出异常,所以 error 将不会有返回值
// never 类型表示永远不会有值的一种类型
function error(message: string): never {
    throw new Error(message);
}

TS和JS相比有什么区别

TypeScript(TS)和JavaScript(JS)相比,主要的区别体现在以下几个方面:

1. 类型系统:

  • TypeScript 是一种静态类型的编程语言,它增加了静态类型系统,允许开发者在编写代码时定义变量、参数和返回值的类型。这种类型检查有助于防止类型相关的错误,提高代码的可读性和可维护性。
  • JavaScript 是一种弱类型的编程语言,对使用的数据类型没有严格的要求,变量可以随时改变类型。
    2.面向对象:
  • TypeScript 是一种面向对象的编程语言,它支持类、接口和模块等面向对象编程的概念,适合开发大型应用。
  • JavaScript 虽然也可以实现面向对象编程,但通常更被认为是基于对象的脚本语言。
    3.编译与解释:
  • TypeScript 需要编译成 JavaScript 才能运行,这提供了更好的类型检查和代码优化。
  • JavaScript 是一种解释型脚本语言,代码不需要编译即可执行。
    4.规模和复杂性:
  • TypeScript 更适合用于开发大型的应用,因为大型应用需要模块的集成和易于维护。
  • JavaScript 在小型应用中可能更受欢迎,因为它更轻量且开发效率高。
    5.扩展性:
  • TypeScript 是 JavaScript 的超集,包含了 JavaScript 的所有元素,可以载入 JavaScript 代码运行,并扩展了 JavaScript 的语法。
  • JavaScript 本身也有其独特的语法和功能。
    6.工具和生态系统:
  • 由于 TypeScript 的静态类型特性,它更容易与IDE和其他工具集成,提供更好的代码提示和重构功能。
  • JavaScript 的生态系统非常庞大,有大量的库和框架可供选择。

总的来说,TypeScriptJavaScript 各有其优势和适用场景。TypeScript 提供了更强的类型检查和面向对象编程的支持,适合大型、复杂的项目;而 JavaScript 则更轻量、灵活,适合小型、快速迭代的项目。选择哪种语言取决于项目的具体需求和团队的偏好。

当异步操作返回的数据格式不清楚,你如何用TS定义

如果你的函数需要处理多种不同但未知的数据格式,你可以使用泛型来让调用者指定返回数据的类型。

async function fetchData<T>(): Promise<T> {  
  // 假设这是一个泛型的异步API调用  
  const response = await someGenericApiCall<T>();  
  return response;  
}  
  
// 调用函数时指定返回数据的类型  
fetchData<MyKnownType>().then((data) => {  
  // 这里你可以安全地访问 MyKnownType 上的所有属性,因为你在调用时指定了它  
  console.log(data.propertyOfMyKnownType);  
}).catch((error) => {  
  console.error('Error fetching data:', error);  
});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值