3 個加強理解TypeScript 的面試問題

TypeScript 作為 JavaScript 的超集,讓 JavaScript 越來越像一門“正經的”語言。和純粹的 JavaScript 語言相比,TypeScript 提供靜態的類型檢查,提供類的語法糖(這一點是繼承了 ES6 的實現),讓程序更加規范和緊湊,為使用 JavaScript 開發大型項目提供了必要的條件。本文介紹 3 個加強理解的面試問題。
A 的類型是什么,為什么?
通常在面試中會有一些閱讀程序語句給出結果的問題,一般是一段非常簡單的代碼,是檢驗候選人對基礎的理解。
type A = number & string;
答案很簡單,A 的類型是 never,為什么呢?因為 & 是交集運算符,如果將字符串和數字視為一組值,則可以對其進行賦值。那么字符串集合和數字集合的交集是空集,在 TypeScript 中用 never 表示,換句話說,不存在可以同時屬于數字和字符串的值:

運行時驗證
假設候選人成功回答了第一個問題,這意味著大概率候選人對基礎有了很好的理解。現在,需要變得更復雜一點,變得非常實際:假設有一個 API,它返回給我們一個 JSON 字符串,其中包含有關用戶的信息。
問題是:如何驗證用戶對象,并確保它確實滿足
User類型?
type User = {
name: string;
age: number;
};
const data = `{"name":"Bob","age":30}`;
const user: User = JSON.parse(data);
console.log(`Username: ${user.name.toLowerCase()}`);
console.log(`Age: ${user.age.toFixed(0)}`);
答案基本上有兩種方式:
首先,如果 User 類型很小,比如現在只有兩個字段,這對我們來說沒問題,那么我們可以編寫一個簡單的驗證函數:
function isUser(obj: unknown): obj is User {
return (
typeof obj['name'] === 'string' &&
typeof obj['age'] === 'number'
);
}
并像這樣使用它:
const data = `{"name":"Bob","age":30}`;
const user = JSON.parse(data); // user type if any here
if (isUser(user)) {
console.log(`Username: ${user.name.toLowerCase()}`);
console.log(`Age: ${user.age.toFixed(0)}`);
}
第二種變體,它更方便——使用你喜歡的任何庫來使用模式驗證:class-validator、zod、runtypes、joi 等:
import Joi from "joi";
const UserSchema = Joi.object({
name: Joi.string(),
age: Joi.number(),
});
const data = `{"name":"Bob","age":30}`;
const userData = JSON.parse(data);
try {
const user = UserSchema.validate(userData);
console.log(`Username: ${user.name.toLowerCase()}`);
console.log(`Age: ${user.age.toFixed(0)}`);
} catch (e) {}
這個問題不僅要檢查有關數據驗證的知識,還要檢查候選人對技術堆棧的了解程度,可以通過哪些方式完成等。
在類型中使用遞歸
最后一個問題通常是實用的,它是關于如何編寫遞歸類型的。在此示例中,需要問題的解決方案:假設正在編寫一個函數 find() 來搜索數據庫中的用戶。問題是該類型 User 具有地址等屬性,它也是一個對象。想以 find() 這種方式構建函數,這樣可以通過 User 的嵌套屬性進行搜索,并提供完整的類型支持:
function find<T>(criteria: ...): T[] {
...
}
type User = {
id: number;
name: string;
address: {
country: string;
city: string;
house: string;
zipcode: string;
};
};
// in this example im searching by country only, even if
// address has other properties.
const users = find({
address: { coutry: 'CN' }
});
如何實現:創建另一個名為 DeepPartial 的類型,并在 find() 函數中使用它作為條件參數:
type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
function find<T>(criteria: DeepPartial<T>): T[] {
...
}
type User = {
id: number;
name: string;
address: {
country: string;
city: string;
house: string;
zipcode: string;
};
};
const users = find({
address: { coutry: 'UK' }
});
DeepPartial<T> 幾乎與 Partial<T> 一樣工作,但唯一的區別是它遞歸地應用于對象的每個嵌套屬性:
type User = {
id: number;
name: string;
address: {
country: string;
city: string;
house: string;
zipcode: string;
};
};
// DeepPartial<User>
type DeepPartiallUser = {
id?: number;
name?: string;
address?: {
country?: string;
city?: string;
house?: string;
zipcode?: string;
};
};
希望通過上面這些 TypeScript 的小例子可以幫助更好地使用它,并且在還不知道這些東西的情況下寫出更好的代碼。