钉钉前端面试题~TypeScript相关问题及解答

全栈前端精选

共 2094字,需浏览 5分钟

 ·

2021-11-16 09:12

给出一大些面试题,然后不给答案。前端本来就卷,一些面试官看了文章后可能在自己都不知道答案的情况下,就跑去问面试者。我其实挺反感的这类文章的。

😊 ts中的访问修饰符

  • public,任何地方
  • private,只能在类的内部访问
  • protected,能在类的内部访问和子类中访问
  • readonly,属性设置为只读

😊 const和readonly的区别

  1. const用于变量,readonly用于属性
  2. const在运行时检查,readonly在编译时检查
  3. 使用const变量保存的数组,可以使用push,pop等方法。但是如果使用ReadonlyArray声明的数组不能使用push,pop等方法。

😊 枚举和常量枚举(const枚举)的区别

  1. 枚举会被编译时会编译成一个对象,可以被当作对象使用
  2. const枚举会在ts编译期间被删除,避免额外的性能开销
// 普通枚举
enum Witcher {
  Ciri = 'Queen',
  Geralt = 'Geralt of Rivia'
}
function getGeraltMessage(arg: {[key: string]: string}): string {
  return arg.Geralt
}
getGeraltMessage(Witcher) // Geralt of Rivia
复制代码
// const枚举
const enum Witcher {
  Ciri = 'Queen',
  Geralt = 'Geralt of Rivia'
}
const witchers: Witcher[] = [Witcher.Ciri, Witcher.Geralt]
// 编译后
// const witchers = ['Queen', 'Geralt of Rivia'
复制代码

😊 ts中interface可以给Function/Array/Class做声明吗?

// 函数类型
interface SearchFunc {
  (source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string{
  let result = source.search(subString);
  return result > -1;
}
复制代码
// Array
interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob""Fred"];
复制代码
// Class, constructor存在于类的静态部分,所以不会检查
interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
}

class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
        this.currentTime = d;
    }
    constructor(h: number, m: number) { }
}
复制代码

ts中的this和js中的this有什么差异?

不了解

😊 ts中如何枚举联合类型的key?

type Name = { name: string }
type Age = { age: number }
type Union = Name | Age

type UnionKey

 = P extends infer P ? keyof P : never

type T = UnionKey
复制代码

😊 ts中 ?.、??、!.、_、** 等符号的含义?

  • ?. 可选链
  • ?? ?? 类似与短路或,??避免了一些意外情况0,NaN以及"",false被视为false值。只有undefind,null被视为false值。
  • !. 在变量名后添加!,可以断言排除undefined和null类型
  • _ , 声明该函数将被传递一个参数,但您并不关心它
  • ** 求幂
  • !:,待会分配这个变量,ts不要担心
// ??
let x = foo ?? bar();
// 等价于
let x = foo !== null && foo !== undefined ? foo : bar();

// !.
let a: string | null | undefined
a.length // error
a!.length // ok
复制代码

😊 什么是抗变、双变、协变和逆变?

  • Covariant 协变,TS对象兼容性是协变,父类 <= 子类,是可以的。子类 <= 父类,错误。
  • Contravariant 逆变,禁用strictFunctionTypes编译,函数参数类型是逆变的,父类 <= 子类,是错误。子类 <= 父类,是可以的。
  • Bivariant 双向协变,函数参数的类型默认是双向协变的。父类 <= 子类,是可以的。子类 <= 父类,是可以的。

😊 ts中同名的interface或者同名的interface和class可以合并吗?

  1. interface会合并
  2. class不可以合并

😊 如何使ts项目引入并识别编译为js的npm库包?

  1. npm install @types/xxxx
  2. 自己添加描述文件

😊 ts如何自动生成库包的声明文件?

可以配置tsconfig.json文件中的declarationoutDir

  1. declaration: true, 将会自动生成声明文件
  2. outDir: '', 指定目录

😊 什么是泛型

泛型用来来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。简单的说,“泛型就是把类型当成参数”。

😊 -?,-readonly 是什么含义

用于删除修饰符

type A = {
    a: string;
    b: number;
}

type B = {
    [K in keyof A]?: A[K]
}

type C = {
    [K in keyof B]-?: B[K]
}

type D = {
    readonly [K in keyof A]: A[K]
}

type E = {
    -readonly [K in keyof A]: A[K]
}
复制代码

😊 TS是基于结构类型兼容

typescript的类型兼容是基于结构的,不是基于名义的。下面的代码在ts中是完全可以的,但在java等基于名义的语言则会抛错。

interface Named { name: string }
class Person {
  name: string
}
let p: Named
// ok
p = new Person()
复制代码

😊 const断言

const断言,typescript会为变量添加一个自身的字面量类型

  1. 对象字面量的属性,获得readonly的属性,成为只读属性
  2. 数组字面量成为readonly tuple只读元组
  3. 字面量类型不能被扩展(比如从hello类型到string类型)
// type '"hello"'
let x = "hello" as const
// type 'readonly [10, 20]'
let y = [1020as const
// type '{ readonly text: "hello" }'
let z = { text: "hello" } as const
复制代码

😊 type 和 interface 的区别

  1. 类型别名可以为任何类型引入名称。例如基本类型,联合类型等
  2. 类型别名不支持继承
  3. 类型别名不会创建一个真正的名字
  4. 类型别名无法被实现(implements),而接口可以被派生类实现
  5. 类型别名重名时编译器会抛出错误,接口重名时会产生合并

😊 implements 与 extends 的区别

  • extends, 子类会继承父类的所有属性和方法。
  • implements,使用implements关键字的类将需要实现需要实现的类的所有属性和方法。

😊 枚举和 object 的区别

  1. 枚举可以通过枚举的名称,获取枚举的值。也可以通过枚举的值获取枚举的名称。
  2. object只能通过key获取value
  3. 数字枚举在不指定初始值的情况下,枚举值会从0开始递增。
  4. 虽然在运行时,枚举是一个真实存在的对象。但是使用keyof时的行为却和普通对象不一致。必须使用keyof typeof才可以获取枚举所有属性名。

😊 never, void 的区别

  • never,never表示永远不存在的类型。比如一个函数总是抛出错误,而没有返回值。或者一个函数内部有死循环,永远不会有返回值。函数的返回值就是never类型。
  • void, 没有显示的返回值的函数返回值为void类型。如果一个变量为void类型,只能赋予undefined或者null。

unknown, any的区别

unknown类型和any类型类似。与any类型不同的是。unknown类型可以接受任意类型赋值,但是unknown类型赋值给其他类型前,必须被断言

😊 如何在 window 扩展类型

declare global {
  interface Window {
    myCustomFn: () => void;
  }
}
复制代码

复杂的类型推导题目

🤔 implement UnionToIntersection

type A = UnionToIntersection<{a: string} | {b: string} | {c: string}> 
// {a: string} & {b: string} & {c: string}

// 实现UnionToIntersection
type UnionToIntersection = 
  (extends any ? (k: U) => void : neverextends ((k: infer I) => void) ? I : never
// https://stackoverflow.com/questions/50374908/transform-union-type-to-intersection-type
// https://jkchao.github.io/typescript-book-chinese/tips/infer.html#%E4%B8%80%E4%BA%9B%E7%94%A8%E4%BE%8B
复制代码

😊 implement ToNumber

type A = ToNumber<'1'// 1
type B = ToNumber<'40'// 40
type C = ToNumber<'0'// 0

// 实现ToNumber
type ToNumberextends string, R extends any[] = []> =
    T extends `${R['length']}` ? R['length'] : ToNumber1, ...R]>;
复制代码

😊 implement Add

type A = Add<12// 3
type B = Add<00// 0

// 实现ADD
type NumberToArrayextends any[]> = T extends R['length'] ? R : NumberToArray1, ...R]>
type Add = [...NumberToArray, ...NumberToArray]['length']
复制代码

😊 implement SmallerThan

type A = SmallerThan<01// true
type B = SmallerThan<10// false
type C = SmallerThan<109// false

// 实现SmallerThan
type SmallerThanextends number, M extends number, L extends any[] = [], R extends any[] = []> = 
    N extends L['length'] ? 
        M extends R['length'] ? false : true
        :
        M extends R['length'] ? false : SmallerThan1, ...L], [1, ...R]>;
复制代码

😊 implement LargerThan

type A = LargerThan<01// false
type B = LargerThan<10// true
type C = LargerThan<109// true

// 实现LargerThan
type LargerThanextends number, M extends number, L extends any[] = [], R extends any[] = []> =
    N extends L['length'] ?
        false : M extends R['length'] ?
            true : LargerThan1, ...L], [1, ...R]>;
复制代码

😊 implement IsAny

type A = IsAny<string// false
type B = IsAny<any// true
type C = IsAny // false
type D = IsAny // false

// 实现IsAny
type IsAny = true extends (T extends never ? true : false) ?
                  false extends (T extends never ? true : false) ?
                    true
                    :
                    false
                  :
                  false;

// 更简单的实现
type IsAny = 0 extends (T & 1) ? true : false;
复制代码

😊 implement Filter

type A = Filter<[1,'BFE'2true'dev'], number// [1, 2]
type B = Filter<[1,'BFE'2true'dev'], string// ['BFE', 'dev']
type C = Filter<[1,'BFE'2any'dev'], string// ['BFE', any, 'dev']

// 实现Filter
type Filterextends any[], A, N extends any[] = []> =
    T extends [infer P, ...infer Q] ?
        0 extends (P & 1) ? Filter : 
        P extends A ? Filter : Filter
        : N;
复制代码

😊 implement TupleToString

type A = TupleToString<['a']> // 'a'
type B = TupleToString<['B''F''E']> // 'BFE'
type C = TupleToString<[]> // ''

// 实现TupleToString
type TupleToStringextends any[], S extends string = '', A extends any[] = []> =
    A['length'extends T['length'] ? S : TupleToString`${S}${T[A['length']]}`, [1, ...A]>
复制代码

😊 implement RepeatString

type A = RepeatString<'a'3// 'aaa'
type B = RepeatString<'a'0// ''

// 实现RepeatString
type RepeatStringextends string, C extends number, S extends string = '', A extends any[] = []> =
    A['length'extends C ? S : RepeatString`${T}${S}`, [1, ...A]>
复制代码

😊 implement Push

type A = Push<[1,2,3], 4// [1,2,3,4]
type B = Push<[1], 2// [1, 2]
type C = Push<[], string// [string]

// 实现Push
type Pushextends any[], I> = T extends [...infer P] ? [...P, I] : [I]
复制代码

😊 implement Flat

type A = Flat<[1,2,3]> // [1,2,3]
type B = Flat<[1,[2,3], [4,[5,[6]]]]> // [1,2,3,4,5,6]
type C = Flat<[]> // []

// 实现Flat
type Flatextends any[]> =
    T extends [infer P, ...infer Q] ?
        P extends any[] ? [...Flat

, ...Flat] : [P, ...Flat]
        : [];
复制代码

😊 implement Shift

type A = Shift<[1,2,3]> // [2,3]
type B = Shift<[1]> // []
type C = Shift<[]> // []

// 实现Shift
type Shiftextends any[]> = T extends [infer P, ...infer Q] ? [...Q] : [];
复制代码

😊 implement Repeat

type A = Repeat<number3// [number, number, number]
type B = Repeat<string2// [string, string]
type C = Repeat<11// [1, 1]
type D = Repeat<00// []

// 实现Repeat
type Repeatextends any[] = []> = 
    R['length'extends C ? R : Repeat
复制代码

😊 implement ReverseTuple

type A = ReverseTuple<[stringnumberboolean]> // [boolean, number, string]
type B = ReverseTuple<[1,2,3]> // [3,2,1]
type C = ReverseTuple<[]> // []

// 实现ReverseTuple
type ReverseTupleextends any[], A extends any[] = []> =
    T extends [...infer Q, infer P] ? 
        A['length'extends T['length'] ? A : ReverseTuple
        : A;
复制代码

😊 implement UnwrapPromise

type A = UnwrapPromise<Promise<string>> // string
type B = UnwrapPromise<Promise<null>> // null
type C = UnwrapPromise<null// Error

// 实现UnwrapPromise
type UnwrapPromise = T extends Promise ? P : Error;
复制代码

😊 implement LengthOfString

type A = LengthOfString<'BFE.dev'// 7
type B = LengthOfString<''// 0

// 实现LengthOfString
type LengthOfStringextends string, A extends any[] = []> =
    T extends `${infer P}${infer Q}` ? LengthOfString1, ...A]> : A['length']
复制代码

😊 implement StringToTuple

type A = StringToTuple<'BFE.dev'// ['B', 'F', 'E', '.', 'd', 'e','v']
type B = StringToTuple<''// []

// 实现
type StringToTupleextends string, A extends any[] = []> =
    T extends `${infer K}${infer P}` ? StringToTuple : A;
复制代码

😊 implement LengthOfTuple

type A = LengthOfTuple<['B''F''E']> // 3
type B = LengthOfTuple<[]> // 0

// 实现
type LengthOfTupleextends any[], R extends any[] = []> =
    R['length'extends T['length'] ? R['length'] : LengthOfTuple1]>
复制代码

😊 implement LastItem

type A = LastItem<[stringnumberboolean]> // boolean
type B = LastItem<['B''F''E']> // 'E'
type C = LastItem<[]> // never

// 实现LastItem
type LastItem = T extends [...infer P, infer Q] ? Q : never;
复制代码

😊 implement FirstItem

type A = FirstItem<[stringnumberboolean]> // string
type B = FirstItem<['B''F''E']> // 'B'

// 实现FirstItem
type FirstItem = T extends [infer P, ...infer Q] ? P : never;
复制代码

😊 implement FirstChar

type A = FirstChar<'BFE'// 'B'
type B = FirstChar<'dev'// 'd'
type C = FirstChar<''// never

// 实现FirstChar
type FirstChar = T extends `${infer P}${infer Q}` ? P : never;
复制代码

😊 implement Pick

type Foo = {
  a: string
  b: number
  c: boolean
}

type A = MyPick'a' | 'b'// {a: string, b: number}
type B = MyPick'c'> // {c: boolean}
type C = MyPick'd'> // Error

// 实现MyPick
type MyPickextends keyof T> = {
    [Key in K]: T[Key]
}
复制代码

😊 implement Readonly

type Foo = {
  a: string
}

const a:Foo = {
  a: 'BFE.dev',
}
a.a = 'bigfrontend.dev'
// OK

const b:MyReadonly = {
  a: 'BFE.dev'
}
b.a = 'bigfrontend.dev'
// Error

// 实现MyReadonly
type MyReadonly = {
    readonly [K in keyof T]: T[K]
}
复制代码

😊 implement Record

type Key = 'a' | 'b' | 'c'

const a: Recordstring> = {
  a: 'BFE.dev',
  b: 'BFE.dev',
  c: 'BFE.dev'
}
a.a = 'bigfrontend.dev' // OK
a.b = 123 // Error
a.d = 'BFE.dev' // Error

type Foo = MyRecord<{a: string}, string// Error

// 实现MyRecord
type MyRecordextends number | string | symbol, V> = {
    [Key in K]: V
}
复制代码

🤔️ implement Exclude

type Foo = 'a' | 'b' | 'c'

type A = MyExclude'a'> // 'b' | 'c'
type B = MyExclude'c'> // 'a' | 'b
type C = MyExclude'c' | 'd'>  // 'a' | 'b'
type D = MyExclude'a' | 'b' | 'c'>  // never

// 实现 MyExclude
type MyExclude = T extends K ? never : T;
复制代码

🤔️ implement Extract

type Foo = 'a' | 'b' | 'c'

type A = MyExtract'a'> // 'a'
type B = MyExtract'a' | 'b'// 'a' | 'b'
type C = MyExtract'b' | 'c' | 'd' | 'e'>  // 'b' | 'c'
type D = MyExtract  // never

// 实现MyExtract
type MyExtract = T extends U ? T : never
复制代码

😊 implement Omit

type Foo = {
  a: string
  b: number
  c: boolean
}

type A = MyOmit'a' | 'b'// {c: boolean}
type B = MyOmit'c'> // {a: string, b: number}
type C = MyOmit'c' | 'd'// {a: string, b: number}

// 实现MyOmit
type MyOmitextends number | string | symbol> = {
    [Key in Exclude]: T[Key]
}

type MyOmitextends number | string | symbol> = Pick>
复制代码

😊 implement NonNullable

type Foo = 'a' | 'b' | null | undefined

type A = MyNonNullable // 'a' | 'b'

// 实现NonNullable
type MyNonNullable = T extends null | undefined ? never : T;
复制代码

😊 implement Parameters

type Foo = (a: string, b: number, c: boolean) => string

type A = MyParameters // [a:string, b: number, c:boolean]
type B = A[0// string
type C = MyParameters<{a: string}> // Error

// 实现MyParameters
type MyParametersextends (...params: any[]) => any> =
    T extends (...params: [...infer P]) => any ? P : never
复制代码

😊 implement ConstructorParameters

class Foo {
  constructor (a: string, b: number, c: boolean) {}
}

type C = MyConstructorParameters<typeof Foo> 
// [a: string, b: number, c: boolean]

// 实现MyConstructorParameters
type MyConstructorParametersextends new (...params: any[]) => any> =
    T extends new (...params: [...infer P]) => any ? P : never
复制代码

😊 implement ReturnType

type Foo = () => {a: string}

type A = MyReturnType // {a: string}

// 实现MyReturnType
type MyReturnTypeextends (...params: any[]) => any> =
    T extends (...params: any[]) => infer P ? P : never;
复制代码

😊 implement InstanceType

class Foo {}
type A = MyInstanceType<typeof Foo> // Foo
type B = MyInstanceType<() => string// Error

// 实现MyInstanceType
type MyInstanceTypeextends new (...params: any[]) => any> =
    T extends new (...params: any[]) => infer P ? P : never;
复制代码

😊 implement ThisParameterType

function Foo(this: {a: string}{}
function Bar() {}

type A = MyThisParameterType<typeof Foo> // {a: string}
type B = MyThisParameterType<typeof Bar> // unknown

// 实现MyThisParameterType
type MyThisParameterTypeextends (thisany, ...params: any[]) => any> =
    T extends (this: infer P, ...params: any[]) => any ? P : unknown;
复制代码

😊 implement TupleToUnion

type Foo = [stringnumberboolean]

type Bar = TupleToUnion // string | number | boolean

// 实现TupleToUnion
type TupleToUnionextends any[], R = T[0]> =
    T extends [infer P, ...infer Q] ? TupleToUnion : R;

// 其他回答
type TupleToUnionextends any[]> = T[number]
复制代码

😊 implement Partial

type Foo = {
  a: string
  b: number
  c: boolean
}

// below are all valid

const a: MyPartial = {}

const b: MyPartial = {
  a: 'BFE.dev'
}

const c: MyPartial = {
  b: 123
}

const d: MyPartial = {
  b: 123,
  c: true
}

const e: MyPartial = {
  a: 'BFE.dev',
  b: 123,
  c: true
}

// 实现MyPartial
type MyPartial = {
    [K in keyof T]?: T[K]
}
复制代码

😊 Required

// all properties are optional
type Foo = {
  a?: string
  b?: number
  c?: boolean
}


const a: MyRequired = {}
// Error

const b: MyRequired = {
  a: 'BFE.dev'
}
// Error

const c: MyRequired = {
  b: 123
}
// Error

const d: MyRequired = {
  b: 123,
  c: true
}
// Error

const e: MyRequired = {
  a: 'BFE.dev',
  b: 123,
  c: true
}
// valid

// 实现MyRequired
type MyRequired = {
    [K in keyof T]-?: T[K]
}
复制代码

😊 implement LastChar

type A = LastChar<'BFE'// 'E'
type B = LastChar<'dev'// 'v'
type C = LastChar<''// never

// 实现FirstChar
type LastCharextends string, A extends string[] = []> =
    T extends `${infer P}${infer Q}` ?  LastChar :
        A extends [...infer L, infer R] ? R : never
;
复制代码

😊 implement IsNever

// https://stackoverflow.com/questions/53984650/typescript-never-type-inconsistently-matched-in-conditional-type
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#v
type A = IsNever // true
type B = IsNever<string// false
type C = IsNever<undefined// false

// 实现IsNever
type IsNever = [T] extends [never] ? true : false;
复制代码

😊 implement KeysToUnion

type A = KeyToUnion<{
  a: string;
  b: number;
  c: symbol;
}>
// 'a' | 'b' | 'c'

// 实现KeyToUnion
type KeyToUnion = {
  [K in keyof T]: K;
}[keyof T]
复制代码

😊 implement ValuesToUnion

type A = ValuesToUnion<{
  a: string;
  b: number;
  c: symbol;
}>
// string | number | symbol

// ValuesToUnion
type ValuesToUnion = T[keyof T]
复制代码

FindIndex

bigfrontend.dev/zh/typescri…[2]

type IsAny = 0 extends (T & 1) ? true : false;
type IsNever = [T] extends [never] ? true : false;

type TwoAny = IsAny extends IsAny ? IsAny : false;
type TwoNever = IsNever
 extends IsNever ? IsNever : false;

type SingleAny = IsAny
 extends true ? true : IsAny
type SingleNever = IsNever
 extends true ? true : IsNever


type FindIndexextends any[], E, A extends any[] = []> =
    T extends [infer P, ...infer Q] ?
        TwoAny extends true ? 
            A['length']
            :
            TwoNever extends true ?
                A['length']
                :
                SingleAny extends true ?
                    FindIndex1, ...A]>
                    :
                    SingleNever extends true ?
                        FindIndex1, ...A]>
                        :
                        P extends E ? A['length'] : FindIndex1, ...A]>
        : 
        never
复制代码

implement Trim

type A = Trim<'    BFE.dev'// 'BFE'
type B = Trim<' BFE. dev  '// 'BFE. dev'
type C = Trim<'  BFE .   dev  '// 'BFE .   dev'

type StringToTupleextends string, A extends any[] = []> =
    T extends `${infer K}${infer P}` ? StringToTuple : A;

type TupleToStringextends any[], S extends string = '', A extends any[] = []> =
    A['length'extends T['length'] ? S : TupleToString`${S}${T[A['length']]}`, [1, ...A]>

type Trimextends string, A extends any[] = StringToTuple> =
    A extends [infer P, ...infer Q] ?
        P extends ' ' ?
            Trim
            :
            A extends [...infer M, infer N] ? 
                N extends ' ' ?
                    Trim
                    :
                    TupleToString

                :
                ''
        :
        '';
复制代码

还有更多 UnionToTupleIntersectionToUnion ?


关于本文

作者:dyhtps

https://juejin.cn/post/6988763249982308382

浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报