我要漲知識 —— TypeScript 常見面試題(一)

1、ts 中的 any 和 unknown 有什麼區別?

unknown 和 any 的主要區別是 unknown 類型會更加嚴格:在對 unknown 類型的值執行大多數操作之前,我們必須進行某種形式的檢查。而在對 any 類型的值執行操作之前,我們不必進行任何檢查。

舉例說明:

let foo: any = 123;
console.log(foo.msg); // 符合TS的語法
let a_value1: unknown = foo; // OK
let a_value2: any = foo; // OK
let a_value3: string = foo; // OK
let bar: unknown = 222; // OK 
console.log(bar.msg); // Error
let k_value1: unknown = bar; // OK
let K_value2: any = bar; // OK
let K_value3: string = bar; // Error

  

因為bar是一個未知類型(任何類型的數據都可以賦給 unknown 類型),所以不能確定是否有msg屬性。不能通過TS語法檢測;而 unknown 類型的值也不能將值賦給 any 和 unknown 之外的類型變量

總結:

any 和 unknown 都是頂級類型,但是 unknown 更加嚴格,不像 any 那樣不做類型檢查,反而 unknown 因為未知性質,不允許訪問屬性,不允許賦值給其他有明確類型的變量。

2、說說你對 typescript 的理解?與 javascript 的區別?

2.1、TS是什麼?

TypeScript 是 JavaScript 的類型的超集,支持ES6語法,支持面向對象編程的概念,如類、接口、繼承、泛型等

超集,不得不說另外一個概念,子集,怎麼理解這兩個呢,舉個例子,如果一個集合A裏面的的所有元素集合B裏面都存在,那麼我們可以理解集合B是集合A的超集,集合A為集合B的子集

其是一種靜態類型檢查的語言,提供了類型註解,在代碼編譯階段就可以檢查出數據類型的錯誤

同時擴展了JavaScript 的語法,所以任何現有的JavaScript 程序可以不加改變的在 TypeScript 下工作

為了保證兼容性,typescript在編譯階段需要編譯器編譯成純Javascript來運行,是為大型應用之開發而設計的語言,如下:

tsx文件如下:

const hello : string = "Hello World!"
console.log(hello)
複製代碼

編譯文件後:

const hello = "Hello World!"
console.log(hello)
複製代碼

2.2、特性

typescript的特性主要有如下:

  • 類型批註和編譯時類型檢查 :在編譯時批註變量類型
  • 類型推斷:ts中沒有批註變量類型會自動推斷變量的類型
  • 類型擦除:在編譯過程中批註的內容和接口會在運行時利用工具擦除
  • 接口:ts中用接口來定義對象類型
  • 枚舉:用於取值被限定在一定範圍內的場景
  • Mixin:可以接受任意類型的值
  • 泛型編程:寫代碼時使用一些以後才指定的類型
  • 名字空間:名字只在該區域內有效,其他區域可重複使用該名字而不衝突
  • 元組:元組合併了不同類型的對象,相當於一個可以裝不同類型數據的數組

2.3、類型批註

通過類型批註提供在編譯時啟動類型檢查的靜態類型,這是可選的,而且可以忽略而使用JavaScript常規的動態類型

function Add(left: number, right: number): number {
 return left + right;
}
對於基本類型的批註是number、bool和string,而弱或動態類型的結構則是any類型

2.4、類型推斷

當類型沒有給出時,TypeScript編譯器利用類型推斷來推斷類型,如下:

let str = 'string'

變量str被推斷為字符串類型,這種推斷髮生在初始化變量和成員,設置默認參數值和決定函數返回值時

如果由於缺乏聲明而不能推斷出類型,那麼它的類型被視作默認的動態any類型

2.5、接口

接口簡單來說就是用來描述對象的類型 數據的類型有number、null、string等數據格式,對象的類型就是用接口來描述的

interface Person {
    name: string;
    age: number;
}

let tom: Person = {
    name: 'Tom',
    age: 25
};

2.6、TS 與 JS 的區別

  • TypeScript 是 JavaScript 的超集,擴展了 JavaScript 的語法
  • TypeScript 可處理已有的 JavaScript 代碼,並只對其中的 TypeScript 代碼進行編譯
  • TypeScript 文件的後綴名 .ts (.ts,.tsx,.dts),JavaScript 文件是 .js
  • 在編寫 TypeScript 的文件的時候就會自動編譯成 js 文件

更多的區別如下圖所示:

3、為什麼推薦使用 TypeScript ?

TypeScript是微軟公司開發和維護的一種面向對象的編程語言。它是JavaScript的超集,包含其所有元素。

強類型和弱類型、靜態類型和動態類型是兩組不同的概念。

類型強弱是針對類型轉換是否顯示來區分,靜態和動態類型是針對類型檢查的時機來區分。

TS對JS的改進主要是靜態類型檢查,靜態類型檢查有何意義?標準答案是「靜態類型更有利於構建大型應用」。

推薦使用TypeScript的原因有:

  • TypeScript簡化了JavaScript代碼,使其更易於閱讀和調試。
  • TypeScript是開源的。
  • TypeScript為JavaScript ide和實踐(如靜態檢查)提供了高效的開發工具。
  • TypeScript使代碼更易於閱讀和理解。
  • 使用TypeScript,我們可以大大改進普通的JavaScript。
  • TypeScript為我們提供了ES6(ECMAScript 6)的所有優點,以及更高的生產率。
  • TypeScript通過對代碼進行類型檢查,可以幫助我們避免在編寫JavaScript時經常遇到的令人痛苦的錯誤。
  • 強大的類型系統,包括泛型。
  • TypeScript只不過是帶有一些附加功能的JavaScript。
  • TypeScript代碼可以按照ES5和ES6標準編譯,以支持最新的瀏覽器。
  • 與ECMAScript對齊以實現兼容性。
  • 以JavaScript開始和結束。
  • 支持靜態類型。
  • TypeScript將節省開發人員的時間。
  • TypeScript是ES3、ES5和ES6的超集。

4、TypeScript 的內置數據類型有哪些?

數字類型:用於表示數字類型的值。TypeScript 中的所有數字都存儲為浮點值。

let identifier: number = value;

布爾類型:一個邏輯二進制開關,包含true或false

let identifier: string = " ";

Null 類型: Null 表示值未定義的變量。

let identifier: bool = Boolean value;

未定義類型:一個未定義的字面量,它是所有變量的起點。

let num: number = null;

void 類型:分配給沒有返回值的方法的類型。

let unusable: void = undefined;

5、TypeScript 中的變量以及如何聲明?

變量是內存中用於存儲值的命名空間。

在 TypeScript 中聲明變量的類型語法在變量名稱後包括一個冒號(:),後跟其類型。 與 JavaScript 相似,我們使用var關鍵字聲明變量。

在Typescript中聲明變量時,必須遵循某些規則:

  • 變量名稱必須是字母或數字。
  • 不能以數字開頭名稱。
  • 除下劃線( _ )和美元( $ )符號外,它不能包含空格和特殊字符。

6、TypeScript 中的泛型是什麼?

TypeScript Generics 是提供創建可重用組件的方法的工具。 它能夠創建可以使用多種數據類型而不是單一數據類型的組件。 而且,它在不影響性能或生產率的情況下提供了類型安全性。 泛型允許我們創建泛型類,泛型函數,泛型方法和泛型接口。

在泛型中,類型參數寫在左括號(<)和右括號(>)之間,這使它成為強類型集合。 它使用一種特殊的類型變量來表示類型。

function identity < T > (arg: T) : T {
    return arg;
}
let output1 = identity < string > ("edureka");
let output2 = identity < number > (117);
console.log(output1);
console.log(output2);

7、TypeScript 中 interface 和 type 的差別是什麼?

7.1、相同點

  • 都可以描述一個對象或者函數
interface User {
    name: string age: number
}
interface SetUser { (name: string, age: number) : void;
}

type User = {
    name: string age: number
};
type SetUser = (name: string, age: number) = >void;
  • 都允許拓展(extends)

interface 和 type 都可以拓展,並且兩者並不是相互獨立的,也就是說 interface 可以 extends type, type 也可以 extends interface 。 雖然效果差不多,但是兩者語法不同。

// 1、interface extends interface
interface Name { 
  name: string; 
}
interface User extends Name { 
  age: number; 
}

// 2、type extends type
type Name = { 
  name: string; 
}
type User = Name & { age: number  };

// 3、interface extends type
type Name = { 
  name: string; 
}
interface User extends Name { 
  age: number; 
}

// 4、type extends interface
interface Name { 
  name: string; 
}
type User = Name & { 
  age: number; 
}

7.2、不同點

  • type 可以而 interface 不行

type 可以聲明基本類型別名,聯合類型,元組等類型

// 基本類型別名
type Name = string

// 聯合類型
interface Dog {
    wong();
}
interface Cat {
    miao();
}

type Pet = Dog | Cat

// 具體定義數組每個位置的類型
type PetList = [Dog, Pet]

type 語句中還可以使用 typeof 獲取實例的 類型進行賦值

// 當你想獲取一個變量的類型時,使用 typeof
let div = document.createElement('div');
type B = typeof div

其他騷操作

type StringOrNumber = string | number;  
type Text = string | { text: string };  
type NameLookup = Dictionary<string, Person>;  
type Callback<T> = (data: T) => void;  
type Pair<T> = [T, T];  
type Coordinates = Pair<number>;  
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
  • interface 可以而 type 不行

interface 能夠聲明合併

interface User {
  name: string
  age: number
}

interface User {
  sex: string
}

/*
User 接口為 {
  name: string
  age: number
  sex: string 
}
*/

一般來說,如果不清楚什麼時候用interface/type,能用 interface 實現,就用 interface , 如果不能就用 type 。

8、TypeScript 的主要特點是什麼?

  • 跨平台:TypeScript 編譯器可以安裝在任何操作系統上,包括 Windows、macOS 和 Linux。
  • ES6 特性:TypeScript 包含計劃中的 ECMAScript 2015 (ES6) 的大部分特性,例如箭頭函數。
  • 面向對象的語言:TypeScript 提供所有標準的 OOP 功能,如類、接口和模塊。
  • 靜態類型檢查:TypeScript 使用靜態類型並幫助在編譯時進行類型檢查。因此,你可以在編寫代碼時發現編譯時錯誤,而無需運行腳本。
  • 可選的靜態類型:如果你習慣了 JavaScript 的動態類型,TypeScript 還允許可選的靜態類型。
  • DOM 操作:您可以使用 TypeScript 來操作 DOM 以添加或刪除客戶端網頁元素。

9、TypeScript 中 never 和 void 的區別

  • void 表示沒有任何類型(可以被賦值為 null 和 undefined)。
  • never 表示一個不包含值的類型,即表示永遠不存在的值。
  • 擁有 void 返回值類型的函數能正常運行。擁有 never 返回值類型的函數無法正常返回,無法終止,或會拋出異常。

10、說一說 TypeScript 中的類及其特性。

TypeScript 引入了類,以便它們可以利用諸如封裝和抽象之類的面向對象技術的好處。

TypeScript 編譯器將 TypeScript 中的類編譯為普通的 JavaScript 函數,以跨平台和瀏覽器工作。

一個類包括以下內容:

  • 構造器(Constructor)
  • 屬性(Properties)
  • 方法(Methods)
class Employee {
    empID: number;
    empName: string;

    constructor(ID: number, name: string) {
        this.empName = name;
        this.empID = ID;
    }

    getSalary(): number {
        return 40000;
    }
}

類的其他特性有:

  • 繼承(Inheritance)
  • 封裝(Encapsulation)
  • 多態(Polymorphism)
  • 抽象(Abstraction)

11、TypeScript 中的類型斷言是什麼?

TypeScript 中的類型斷言的工作方式類似於其他語言中的類型轉換,但沒有 C# 和 Java 等語言中可能的類型檢查或數據重組。類型斷言對運行時沒有影響,僅由編譯器使用。

類型斷言本質上是類型轉換的軟版本,它建議編譯器將變量視為某種類型,但如果它處於不同的形式,則不會強制它進入該模型。

12、TypeScript 中的模塊是什麼?

TypeScript 中的模塊是相關變量、函數、類和接口的集合。 你可以將模塊視為包含執行任務所需的一切的容器。可以導入模塊以輕鬆地在項目之間共享代碼。

module module_name{
  class xyz{
    export sum(x, y){
      return x+y;
    }
  }
}

13、解釋如何使用 TypeScript 中的 mixin。

Mixin 本質上是在相反方向上工作的繼承。Mixins 允許你通過組合以前類中更簡單的部分類設置來構建新類。

相反,類A繼承類B來獲得它的功能,類B從類A需要返回一個新類的附加功能。

14、TypeScript 中什麼是裝飾器,它們可以應用於什麼?

裝飾器是一種特殊的聲明,它允許你通過使用@注釋標記來一次性修改類或類成員。每個裝飾器都必須引用一個將在運行時評估的函數。

例如,裝飾器@sealed將對應於sealed函數。任何標有 的@sealed都將用於評估sealed函數。

function sealed(target) {
  // do something with 'target' ...
}

它們可以附加到:

  • 類聲明
  • 方法
  • 配件
  • 特性
  • 參數

注意:默認情況下不啟用裝飾器。要啟用它們,你必須experimentalDecorators從tsconfig.json文件或命令行編輯編譯器選項中的字段。

15、使用 ts 實現一個判斷入參是否是數組類型的方法?

unknown 用於變量類型不確定,但肯定可以確定的情形下,比如下面這個示例中,入參總歸會有個值,根據這個值的類型進行不同的處理,這裡使用 unknown 替代 any 則會更加類型安全。

function isArray(x: unknown): boolean {
  if (Array.isArray(x)) {
    return true;
  }
  return false;
}