您好,登录后才能下订单哦!
TypeScript(简称TS)是一种由微软开发的开源编程语言,它是JavaScript的超集,添加了可选的静态类型和基于类的面向对象编程。随着TypeScript在前端开发中的广泛应用,越来越多的公司在面试中加入了TypeScript相关的题目。本文将通过几个典型的TS面试题实例代码,深入分析其背后的原理和考察点,帮助读者更好地理解和掌握TypeScript。
let x = 3;
x = "hello"; // 这里会报错吗?
TypeScript具有强大的类型推断能力。在上述代码中,变量x
被初始化为数字3
,TypeScript会自动推断出x
的类型为number
。因此,当尝试将字符串"hello"
赋值给x
时,TypeScript会报错,提示类型不匹配。
let y: number;
y = "hello"; // 这里会报错吗?
在这个例子中,变量y
被显式地注解为number
类型。因此,当尝试将字符串"hello"
赋值给y
时,TypeScript会报错,提示类型不匹配。
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "Alice",
age: 25,
};
person.age = "30"; // 这里会报错吗?
在这个例子中,我们定义了一个Person
接口,它要求name
属性为string
类型,age
属性为number
类型。当尝试将字符串"30"
赋值给person.age
时,TypeScript会报错,因为age
属性的类型应为number
。
type Person = {
name: string;
age: number;
};
const person: Person = {
name: "Bob",
age: 30,
};
person.age = "40"; // 这里会报错吗?
类型别名Person
与接口Person
的功能类似,都用于定义对象的形状。当尝试将字符串"40"
赋值给person.age
时,TypeScript会报错,因为age
属性的类型应为number
。
function identity<T>(arg: T): T {
return arg;
}
const output1 = identity<string>("hello");
const output2 = identity<number>(42);
const output3 = identity("world"); // 这里会报错吗?
在这个例子中,identity
函数是一个泛型函数,它接受一个类型参数T
,并返回相同类型的值。output1
和output2
分别显式地指定了类型参数为string
和number
。output3
没有显式指定类型参数,但TypeScript能够根据传入的参数"world"
推断出类型参数为string
,因此不会报错。
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
const myIdentity: GenericIdentityFn<number> = identity;
const output = myIdentity("hello"); // 这里会报错吗?
在这个例子中,我们定义了一个泛型接口GenericIdentityFn
,它接受一个类型参数T
,并要求实现该接口的函数接受一个类型为T
的参数并返回类型为T
的值。myIdentity
变量被注解为GenericIdentityFn<number>
类型,因此它只能接受number
类型的参数。当尝试将字符串"hello"
传递给myIdentity
时,TypeScript会报错。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(distance: number = 0) {
console.log(`${this.name} moved ${distance}m.`);
}
}
class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}
const dog = new Dog("Rex");
dog.move(10);
dog.bark();
dog.move("20"); // 这里会报错吗?
在这个例子中,Dog
类继承自Animal
类,并添加了一个bark
方法。dog.move(10)
调用Animal
类的move
方法,输出Rex moved 10m.
。dog.bark()
调用Dog
类的bark
方法,输出Woof! Woof!
。当尝试将字符串"20"
传递给dog.move
时,TypeScript会报错,因为move
方法的参数应为number
类型。
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
const padded1 = padLeft("Hello", 4);
const padded2 = padLeft("Hello", " ");
const padded3 = padLeft("Hello", true); // 这里会报错吗?
在这个例子中,padLeft
函数的padding
参数是一个联合类型,可以是string
或number
。padded1
和padded2
分别传递了number
和string
类型的参数,因此不会报错。当尝试将boolean
类型的true
传递给padding
时,TypeScript会报错,因为padding
参数的类型应为string
或number
。
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
type EmployeePerson = Person & Employee;
const employeePerson: EmployeePerson = {
name: "Alice",
employeeId: 123,
};
employeePerson.name = "Bob";
employeePerson.employeeId = "456"; // 这里会报错吗?
在这个例子中,EmployeePerson
类型是Person
和Employee
接口的交叉类型,要求对象同时具有name
和employeeId
属性。employeePerson
对象符合EmployeePerson
类型的定义。当尝试将字符串"456"
赋值给employeePerson.employeeId
时,TypeScript会报错,因为employeeId
属性的类型应为number
。
function isString(value: any): value is string {
return typeof value === "string";
}
function printValue(value: string | number) {
if (isString(value)) {
console.log(`String value: ${value}`);
} else {
console.log(`Number value: ${value}`);
}
}
printValue("hello");
printValue(42);
printValue(true); // 这里会报错吗?
在这个例子中,isString
函数是一个类型守卫函数,用于判断value
是否为string
类型。printValue
函数接受一个string
或number
类型的参数,并根据类型守卫的结果输出不同的信息。当尝试将boolean
类型的true
传递给printValue
时,TypeScript会报错,因为value
参数的类型应为string
或number
。
let someValue: any = "this is a string";
let strLength1: number = (<string>someValue).length;
let strLength2: number = (someValue as string).length;
someValue = 42;
let numLength: number = (someValue as string).length; // 这里会报错吗?
在这个例子中,someValue
变量被注解为any
类型,因此可以赋值任何类型的值。通过类型断言,我们可以将someValue
断言为string
类型,并访问其length
属性。当someValue
被赋值为42
时,尝试将其断言为string
类型并访问length
属性时,TypeScript不会在编译时报错,但在运行时会导致错误。
// math.ts
export function add(x: number, y: number): number {
return x + y;
}
// app.ts
import { add } from "./math";
const result = add(2, 3);
console.log(result);
const result2 = add("2", "3"); // 这里会报错吗?
在这个例子中,math.ts
模块导出了一个add
函数,app.ts
模块通过import
语句引入了add
函数。add
函数接受两个number
类型的参数,并返回它们的和。当尝试将字符串"2"
和"3"
传递给add
函数时,TypeScript会报错,因为add
函数的参数应为number
类型。
namespace MyMath {
export function add(x: number, y: number): number {
return x + y;
}
}
const result = MyMath.add(2, 3);
console.log(result);
const result2 = MyMath.add("2", "3"); // 这里会报错吗?
在这个例子中,MyMath
命名空间定义了一个add
函数,用于计算两个number
类型参数的和。当尝试将字符串"2"
和"3"
传递给MyMath.add
函数时,TypeScript会报错,因为add
函数的参数应为number
类型。
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Calling ${key} with`, args);
const result = originalMethod.apply(this, args);
console.log(`Called ${key}, returned`, result);
return result;
};
return descriptor;
}
class Calculator {
@log
add(x: number, y: number): number {
return x + y;
}
}
const calculator = new Calculator();
const result = calculator.add(2, 3);
console.log(result);
const result2 = calculator.add("2", "3"); // 这里会报错吗?
在这个例子中,log
装饰器用于记录Calculator
类中add
方法的调用和返回结果。add
方法接受两个number
类型的参数,并返回它们的和。当尝试将字符串"2"
和"3"
传递给add
方法时,TypeScript会报错,因为add
方法的参数应为number
类型。
function fetchData(): Promise<string> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data fetched");
}, 1000);
});
}
async function getData() {
const data = await fetchData();
console.log(data);
}
getData();
const data = fetchData();
data.then((result) => console.log(result));
const data2 = fetchData();
data2.then((result) => console.log(result.toFixed())); // 这里会报错吗?
在这个例子中,fetchData
函数返回一个Promise
,在1秒后解析为字符串"Data fetched"
。getData
函数使用async/await
语法等待fetchData
的解析结果,并输出data
。data
和data2
变量分别通过then
方法处理Promise
的解析结果。当尝试调用result.toFixed()
时,TypeScript会报错,因为result
的类型为string
,而toFixed
是number
类型的方法。
Promise
,用于处理异步操作。async/await
语法,简化异步代码的编写。Promise
的解析结果是否符合其定义。interface Named {
name: string;
}
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let p: Named;
p = new Person("Alice", 25); // 这里会报错吗?
在这个例子中,Person
类具有name
和age
属性,而Named
接口只要求name
属性。由于Person
类满足Named
接口的要求,因此可以将Person
类的实例赋值给Named
类型的变量p
,不会报错。
通过以上几个典型的TypeScript面试题实例代码分析,我们可以看到TypeScript在类型推断、类型注解、接口、类型别名、泛型、类与继承、高级类型、类型守卫、类型断言、模块、命名空间、装饰器、异步编程和类型兼容性等方面的强大功能。掌握这些知识点不仅有助于通过面试,还能在实际开发中编写出更加健壮和可维护的代码。希望本文的分析能够帮助读者更好地理解和应用TypeScript。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。