TypeScript面试题收集

330 阅读4分钟

1. TypeScript 与 JavaScript的区别

  • TS 是 JS 的超集
  • 执行环境:node,浏览器都可以直接运行JS,但不能执行TS
  • TS需要编译成JS执行,有编译阶段,JS不需要编译(ES6 -> ES5 那只能叫做转义)
  • 因为有类型的加持,TS能带来更好的开发体验,但是写起来也会更难。
  • 也因为增加了类型,所以在执行之前就能杜绝一些不必要的代码错误(比如写错属性)

2. never 类型有什么作用

知名框架Vue作者的回答: TypeScript中的never类型具体有什么用? - 知乎 (zhihu.com)

never是底类型,他表示永远都不应该出现的类型。

interface Foo {
    type:'foo'
}
interface Bar {
    type:'bar'
}
type All = Foo | Bar

function fn(val:All){
    switch(val:type){
        case 'foo':
            break  //这个分支里面 val 的类型会收窄为Foo
        case 'bar':
            break // 这里的val的类型,会被收窄为Bar
        default:
            const defaultCheck:never = val 
        break
    }
}

在default 分支里面 val 的类型就被收窄为 never,并且赋值给了一个never的变量。never的作用就是,当哪天All的联合类型增加了类型,但是在函数里面没有增加新的分支,那么编译阶段就会报错。

3. any 与 unknown 的区别

  1. 两者都是顶级类型,任何类型的值都可以赋值给顶级变量
  2. any类型什么都不做,意思是可以是任何类型。unknown意思是未知(未知可以理解为不知道怎么在unknown集合里面选出对应的类型)的类型。他要求先收窄类型
const a: unknown = 12 
const b: number = a // 报错

unknown 可以看作是所有类型(不包括any,unknown,never,void)的联合类型

const fn = (a:unknown)=>{
    if(a instanceof Array){
        //array
    }else if(isPerson(a)){
       // person
    }
}

4. enum 的用法

enum Role {
  None = 0,
  Read = 1 << 0,//0001
  Write = 1 << 1, //0010
  Delete = 1 << 2, //0100
  Manage = Read | Write | Delete //0111
}

const user: { permission: Role } = { permission: 0b10001 }
if ((user.permission & Role.Read) === Role.Read) {
  console.log('User can read')
}

枚举类型,一般在枚举的值是数字的时候才好用,其他情况一般不用,因为显得很傻

enum 只能是数字或者字符串

enum Fruit {
    Apple='apple',
    Banana= 'banana'
}
//可以直接用type 代替
type Fruit = 'apple' | 'banana'

5. type 和 interface 的区别

type 用来给其他类型取一个别名

type FalseLike = false | 0 | '' | null | undefined;
const isFalse: FalseLike = '1' //error
  • type 只是给其他类型取一个别名,interface 是类型声明(interface 会创建新的类型名,type 只是创建类型别名,并没有新创建类型。)
  • interface 只描述对象,但是type可以描述所有数据
  • type 不可以重新赋值,interface 则会合并类型去并集
  • 两者拓展的方式不同,interface使用的是extends关键字进行拓展,type使用&进行拓展
  • type声明类型里面可以使用in关键字生成映射类型,但是在interface里面不行
type A = {a:number}
type A = {b:string} //Duplicate identifier 'X'.ts(2300)

interface B {
    b:number
}
interface B {
    c:string
}// 取并集


type Keys = "a" | "b"
interface A { 
  [key in Keys]: string //这里直接报错
}

type 实现继承: type A = B & C (也叫做交叉类型)

6. 联合类型(union types)


type A = { name: string }
type B = { age: number }
type C = A | B

const c: C = { name: 'foo' }

从数学的角度来看,联合类型取得是A和B的 并集

类型收窄

//类型收窄
const fn = (a: number | string) => {
  if (typeof a === 'number') {
    a.toFixed()
  }
  else if (typeof a === 'string') {
    a.toUpperCase()
  }
  else {
    throw new Error('Unexpected type')
  }
}

局限性:

typeof 数组对象,普通对象,null等都会返回 object

instanceof 不支持基础类型。更重要得一点是不支持TS独有得类型

类型谓词(类型判断)


type Rect = {
  width: number
  height: number
}

type Circle = {
  center: [number, number]
  radiuse: number
}

//声明函数来判断,使用 is 关键字
function isRect(x: Rect | Circle): x is Rect {
  return 'height' in x && 'width' in x
}

const f1 = (x: Rect | Circle) => {
  if (isRect(x)) {
    console.log('rect')
  } else {
    console.log('circle')
  }
}
f1({ width: 1, height: 2 })

可辩别联合类型

type Rect = {
  kind: 'rect'
  width: number
  height: number
}

type Circle = {
  kind: 'circle'
  center: [number, number]
  radiuse: number
}

type Shape = Rect | Circle

const f1 = (x: Shape) => {
  if (x.kind === 'rect') {
    console.log('rect')
  } else if (x.kind === 'circle') {
    console.log('circle')
  } else {
    throw new Error('never')
  }
}
f1({ kind: 'rect', width: 1, height: 2 })

将对象类型的收窄,转换成基础类型得对比

7.交叉类型(intersection types)

交叉类型可以理解为求两个类型集合的交集。交叉类型常用于有交集的类型。换句话说,当两个类型没有交集的时候,就会得到never的结果

//得到never
type A = string & number //never

//得到never的属性
type A = { 
    id:string
    age:number
}
type B = {
    id:number
    name:string
}
type C = A & B 

const c:C = {
    id // never
    ...
}

8. as const 是干啥用的

告诉ts将变量按照常量来推导

// 这里定义的数组是 readonly 的,不可以对其进行修改
const compoentSize = ['large','middle','small','mini'] as const 

//Property 'push' does not exist on type 'readonly ["large", "medium", "small", "mini"]'.ts(2339)
componentSize.push('default');
function sum(...array: number[]) {
  const a = [array[0], array[1]] as const
  f1(...a)
}

function f1(a: number, b: number) {
  return a + b
}