Web前端最全TypeScript系列教程五《对象类型》,2024年最新2024前端最新大厂面试真题

文末

如果30岁以前,可以还不知道自己想去做什么的话,那30岁之后,真的觉得时间非常的宝贵,不能再浪费时间在一些碎片化的事情上,比如说看综艺,电视剧。一个人的黄金时间也就二,三十年,不能过得浑浑噩噩。所以花了基本上休息的时间,去不断的完善自己的知识体系,希望可以成为一个领域内的TOP。

同样是干到30岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说30岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端面试题汇总

JavaScript

let myArray: ReadonlyStringArray = getReadOnlyStringArray();

myArray[2] = “Mallory”;Index signature in type ‘ReadonlyStringArray’ only permits reading.Index signature in type ‘ReadonlyStringArray’ only permits reading.尝试

您无法设置myArray[2],因为索引签名是readonly.

扩展类型


拥有可能是其他类型的更具体版本的类型是很常见的。例如,我们可能有一个BasicAddress类型来描述在美国发送信件和包裹所需的字段

interface BasicAddress {

name?: string;

street: string;

city: string;

country: string;

postalCode: string;

}尝试

在某些情况下这就足够了,但如果某个地址的建筑物有多个单元,则地址通常有一个与之关联的单元号。然后我们可以描述一个AddressWithUnit.

interface AddressWithUnit {

name?: string;

unit: string;

street: string;

city: string;

country: string;

postalCode: string;

}尝试

这可以完成这项工作,但这里的缺点是我们必须重复所有其他字段,BasicAddress因为我们的更改是纯粹添加的。相反,我们可以扩展原始BasicAddress类型并添加唯一的新字段AddressWithUnit

interface BasicAddress {

name?: string;

street: string;

city: string;

country: string;

postalCode: string;

}

interface AddressWithUnit extends BasicAddress {

unit: string;

}尝试

an 上的extends关键字interface允许我们有效地从其他命名类型复制成员,并添加我们想要的任何新成员。这对于减少我们必须编写的类型声明样板的数量以及表明同一属性的几个不同声明可能相关的意图很有用。例如,AddressWithUnit不需要重复该street属性,并且由于street源自BasicAddress,读者将知道这两种类型以某种方式相关。

interfaces 也可以从多种类型扩展。

interface Colorful {

color: string;

}

interface Circle {

radius: number;

}

interface ColorfulCircle extends Colorful, Circle {}

const cc: ColorfulCircle = {

color: “red”,

radius: 42,

};尝试

交叉口类型


interfaces 允许我们通过扩展其他类型来构建新类型。TypeScript 提供了另一种称为_交集类型_的构造,主要用于组合现有的对象类型。

使用&运算符定义交集类型。

interface Colorful {

color: string;

}

interface Circle {

radius: number;

}

type ColorfulCircle = Colorful & Circle;尝试

在这里,我们已经相交ColorfulCircle生成了一个新类型,其中包含Colorful Circle的所有成员。

function draw(circle: Colorful & Circle) {

console.log(Color was ${circle.color});

console.log(Radius was ${circle.radius});

}

// okay

draw({ color: “blue”, radius: 42 });

// oops

draw({ color: “red”, raidus: 42 });Argument of type ‘{ color: string; raidus: number; }’ is not assignable to parameter of type ‘Colorful & Circle’.

Object literal may only specify known properties, but ‘raidus’ does not exist in type ‘Colorful & Circle’. Did you mean to write ‘radius’?Argument of type ‘{ color: string; raidus: number; }’ is not assignable to parameter of type ‘Colorful & Circle’.

Object literal may only specify known properties, but ‘raidus’ does not exist in type ‘Colorful & Circle’. Did you mean to write ‘radius’?尝试

接口与交叉点


我们只是研究了两种组合相似但实际上略有不同的类型的方法。使用接口,我们可以使用extends子句从其他类型扩展,我们可以对交集做类似的事情,并用类型别名命名结果。两者之间的主要区别在于如何处理冲突,而这种区别通常是您在接口和交集类型的类型别名之间选择一个而不是另一个的主要原因之一。

通用对象类型


让我们想象一个Box可以包含任何值的类型 - strings、numbers、Giraffes 等等。

interface Box {

contents: any;

}尝试

现在,该contents属性的类型为any,它可以工作,但可能会导致事故发生。

我们可以改为使用unknown,但这意味着在我们已经知道 的类型的情况下contents,我们需要进行预防性检查,或者使用容易出错的类型断言。

interface Box {

contents: unknown;

}

let x: Box = {

contents: “hello world”,

};

// we could check ‘x.contents’

if (typeof x.contents === “string”) {

console.log(x.contents.toLowerCase());

}

// or we could use a type assertion

console.log((x.contents as string).toLowerCase());尝试

一种类型安全的方法是Box为每种类型的contents.

interface NumberBox {

contents: number;

}

interface StringBox {

contents: string;

}

interface BooleanBox {

contents: boolean;

}尝试

但这意味着我们必须创建不同的函数或函数重载,才能对这些类型进行操作。

function setContents(box: StringBox, newContents: string): void;

function setContents(box: NumberBox, newContents: number): void;

function setContents(box: BooleanBox, newContents: boolean): void;

function setContents(box: { contents: any }, newContents: any) {

box.contents = newContents;

}尝试

这是很多样板。此外,我们稍后可能需要引入新的类型和重载。这令人沮丧,因为我们的盒子类型和重载实际上都是相同的。

相反,我们可以创建一个声明_类型参数的**泛型_ 类型。Box

interface Box {

contents: Type;

}尝试

您可能会将其解读为“A BoxofTypecontents具有类型的东西Type”。稍后,当我们引用 时Box,我们必须给出一个_类型参数_来代替Type

let box: Box;尝试

Box其视为真实类型的模板,其中Type占位符将被其他类型替换。当 TypeScript 看到时,它会将in的Box<string>每个实例替换为,并最终使用类似. 换句话说,和我们之前的工作一模一样。Type``Box<Type>``string``{ contents: string }``Box<string>``StringBox

interface Box {

contents: Type;

}

interface StringBox {

contents: string;

}

let boxA: Box = { contents: “hello” };

boxA.contents;

(property) Box.contents: string

let boxB: StringBox = { contents: “world” };

boxB.contents;

(property) StringBox.contents: string尝试

Box可重复使用,Type可以用任何东西代替。这意味着当我们需要一个新类型的盒子时,我们根本不需要声明一个新Box类型(尽管如果我们愿意,我们当然可以)。

interface Box {

contents: Type;

}

interface Apple {

// …

}

// Same as ‘{ contents: Apple }’.

type AppleBox = Box;尝试

这也意味着我们可以通过使用泛型函数来完全避免重载。

function setContents(box: Box, newContents: Type) {

box.contents = newContents;

}尝试

值得注意的是,类型别名也可以是通用的。我们可以定义我们的新Box<Type>接口,它是:

interface Box {

contents: Type;

}尝试

通过使用类型别名来代替:

type Box = {

contents: Type;

};尝试

由于类型别名与接口不同,它可以描述的不仅仅是对象类型,我们也可以使用它们来编写其他类型的通用帮助器类型。

type OrNull = Type | null;

type OneOrMany = Type | Type[];

type OneOrManyOrNull = OrNull<OneOrMany>;

type OneOrManyOrNull = OneOrMany | null

type OneOrManyOrNullStrings = OneOrManyOrNull;

type OneOrManyOrNullStrings = OneOrMany | null尝试

稍后我们将回过头来输入别名。

Array类型_

通用对象类型通常是某种容器类型,它们独立于它们所包含的元素类型工作。数据结构以这种方式工作是理想的,这样它们就可以在不同的数据类型中重用。

事实证明,在这本手册中,我们一直在使用一种类型:Array类型。每当我们写出number[]or之类string[]的类型时,这实际上只是Array<number>and的简写Array<string>

function doSomething(value: Array) {

// …

}

let myArray: string[] = [“hello”, “world”];

// either of these work!

doSomething(myArray);

doSomething(new Array(“hello”, “world”));尝试

很像Box上面的类型,Array它本身就是一个泛型类型。

interface Array {

/**

  • Gets or sets the length of the array.

*/

length: number;

/**

  • Removes the last element from an array and returns it.

*/

pop(): Type | undefined;

/**

  • Appends new elements to an array, and returns the new length of the array.

*/

push(…items: Type[]): number;

// …

}尝试

现代 JavaScript 还提供了其他通用的数据结构,例如Map<K, V>,Set<T>Promise<T>. 所有这一切真正意味着,由于Map,SetPromise行为方式,它们可以与任何类型的集合一起使用。

ReadonlyArray类型_

ReadonlyArray是一种特殊类型,用于描述不应更改的数组。

function doStuff(values: ReadonlyArray) {

// We can read from ‘values’…

const copy = values.slice();

console.log(The first value is ${values[0]});

// …but we can’t mutate ‘values’.

values.push(“hello!”);Property ‘push’ does not exist on type ‘readonly string[]’.Property ‘push’ does not exist on type ‘readonly string[]’.

}尝试

很像readonly属性的修饰符,它主要是我们可以用于意图的工具。当我们看到一个返回ReadonlyArrays 的函数时,它告诉我们根本不打算更改内容,而当我们看到一个使用ReadonlyArrays 的函数时,它告诉我们可以将任何数组传递给该函数,而不必担心它会改变它的内容。

与 不同Array的是,没有ReadonlyArray我们可以使用的构造函数。

new ReadonlyArray(“red”, “green”, “blue”);‘ReadonlyArray’ only refers to a type, but is being used as a value here.‘ReadonlyArray’ only refers to a type, but is being used as a value here.尝试

相反,我们可以将常规Arrays 分配给ReadonlyArrays。

const roArray: ReadonlyArray = [“red”, “green”, “blue”];尝试

正如 TypeScript 为 with 提供简写语法一样,它也为Array<Type>withType[]提供简写ReadonlyArray<Type>语法readonly Type[]

function doStuff(values: readonly string[]) {

// We can read from ‘values’…

const copy = values.slice();

console.log(The first value is ${values[0]});

// …but we can’t mutate ‘values’.

values.push(“hello!”);Property ‘push’ does not exist on type ‘readonly string[]’.Property ‘push’ does not exist on type ‘readonly string[]’.

}尝试

最后要注意的是,与属性修饰符不同,可分配性在常规s 和sreadonly之间不是双向的。Array``ReadonlyArray

let x: readonly string[] = [];

let y: string[] = [];

x = y;

y = x;The type ‘readonly string[]’ is ‘readonly’ and cannot be assigned to the mutable type ‘string[]’.The type ‘readonly string[]’ is ‘readonly’ and cannot be assigned to the mutable type ‘string[]’.尝试

元组类型

_元组类型_是另一种类型Array,它确切地知道它包含多少个元素,以及它在特定位置包含哪些类型。

type StringNumberPair = [string, number];尝试

这里,StringNumberPairstring和的元组类型number。就像ReadonlyArray,它在运行时没有表示,但对 TypeScript 很重要。对于类型系统,描述索引包含 a且索引包含 a的StringNumberPair数组。0``string``1``number

function doSomething(pair: [string, number]) {

const a = pair[0];

const a: string

const b = pair[1];

const b: number

// …

}

doSomething([“hello”, 42]);尝试

如果我们试图索引超过元素的数量,我们会得到一个错误。

function doSomething(pair: [string, number]) {

// …

const c = pair[2];Tuple type ‘[string, number]’ of length ‘2’ has no element at index ‘2’.Tuple type ‘[string, number]’ of length ‘2’ has no element at index ‘2’.

}尝试

我们还可以使用 JavaScript 的数组解构来解构元组。

function doSomething(stringHash: [string, number]) {

const [inputString, hash] = stringHash;

console.log(inputString);

const inputString: string

console.log(hash);

const hash: number

}尝试

元组类型在大量基于约定的 API 中很有用,其中每个元素的含义都是“显而易见的”。这使我们在解构变量时可以灵活地命名变量。在上面的例子中,我们可以命名元素01我们想要的任何东西。

但是,由于并非每个用户都对显而易见的事物持有相同的看法,因此可能值得重新考虑使用具有描述性属性名称的对象是否更适合您的 API。

除了那些长度检查之外,像这样的简单元组类型等价于Array为特定索引声明属性的 s 版本,并length使用数字文字类型声明。

interface StringNumberPair {

// specialized properties

length: 2;

0: string;

1: number;

// Other ‘Array<string | number>’ members…

slice(start?: number, end?: number): Array<string | number>;

}尝试

您可能感兴趣的另一件事是元组可以通过写出问号(?在元素类型之后)来具有可选属性。可选的元组元素只能出现在末尾,也会影响length.

type Either2dOr3d = [number, number, number?];

function setCoordinate(coord: Either2dOr3d) {

const [x, y, z] = coord;

const z: number | undefined

console.log(Provided coordinates had ${coord.length} dimensions);

(property) length: 2 | 3

}尝试

元组也可以有剩余元素,它们必须是数组/元组类型。

type StringNumberBooleans = [string, number, …boolean[]];

type StringBooleansNumber = [string, …boolean[], number];

type BooleansStringNumber = […boolean[], string, number];尝试

  • StringNumberBooleans描述一个元组,其前两个元素分别是stringnumber,但后面可以有任意数量的booleans.

  • StringBooleansNumber描述一个元组,它的第一个元素是string,然后是任意数量的booleans 并以 a 结尾number

  • BooleansStringNumber描述一个元组,其起始元素是任意数量的booleans 并以 a 结尾,string然后是 a number

带有剩余元素的元组没有固定的“长度”——它只有一组位于不同位置的知名元素。

const a: StringNumberBooleans = [“hello”, 1];

const b: StringNumberBooleans = [“beautiful”, 2, true];

const c: StringNumberBooleans = [“world”, 3, true, false, true, false, true];尝试

为什么 optional 和 rest 元素可能有用?好吧,它允许 TypeScript 将元组与参数列表对应起来。元组类型可以用在rest parameters 和 arguments中,这样:

function readButtonInput(…args: [string, number, …boolean[]]) {

const [name, version, …input] = args;

// …

}尝试

最后

好了,这就是整理的前端从入门到放弃的学习笔记,还有很多没有整理到,我也算是边学边去整理,后续还会慢慢完善,这些相信够你学一阵子了。

做程序员,做前端工程师,真的是一个学习就会有回报的职业,不看出身高低,不看学历强弱,只要你的技术达到应有的水准,就能够得到对应的回报。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

学习从来没有一蹴而就,都是持之以恒的,正所谓活到老学到老,真正懂得学习的人,才不会被这个时代的洪流所淘汰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值