我正在享受一種新的(對我而言)將資料模型創建為來自 api 回應的類的模式,因為它們可以具有不一定從 api 回傳的可重用派生邏輯。
我的問題是有多個吸氣劑,我想在相互參考時斷言屬性的存在(或實際上在其他檔案中使用)但沒有,所以我想知道我錯過了什么或更好的解決方案是什么:
type TodoResponse = {
userId: number;
id: number;
title: string;
completed: boolean;
authors?: string[];
}
class Todo implements TodoResponse {
userId!: number;
id!: number;
title!: string;
completed!: boolean;
authors?: string[];
constructor(todo: TodoResponse) {
Object.assign(this, todo);
}
get hasAuthors(): boolean {
return Boolean(this.authors?.length);
}
get firstAuthor(): string | void {
if (this.hasAuthors) return this.authors[0]
// errors with: Object is possibly 'undefined'
}
get firstAuthor(): string | void {
if (this.authors?.length) return this.authors[0]
// this works but it feels redundant to duplicate logic from other getters
}
}
uj5u.com熱心網友回復:
您想要檢查 oftodo.hasAuthors作為型別保護,可用于將型別縮小todo到已知包含已定義authors屬性的內容。不幸的是,TypeScript 目前沒有辦法實作這一點。
首先,不能看到類實作了可區分的聯合型別;否則你可以Todo分配給{hasAuthors: true, authors: string[]} | {hasAuthors: false, authors?: undefined}. 您也許可以使用型別斷言從外部Todo看起來像這樣:
interface TodoWithAuthors extends TodoResponse {
hasAuthors: true,
authors: string[],
firstAuthor: string
}
interface TodoWithoutAuthors extends TodoResponse {
hasAuthors: false,
authors?: undefined,
firstAuthor: void
}
type Todo = TodoWithAuthors | TodoWithoutAuthors;
const Todo = class Todo implements TodoResponse {
/* snip, your original impl goes here */
} as new (todo: TodoResponse) => Todo;
const todo = new Todo({
id: 1, userId: 2, title: "",
completed: false, authors: Math.random() > 0.99 ? undefined : ["a", "b"]
});
if (todo.hasAuthors) {
// no compiler errors here
console.log(todo.authors.join(", ")) // a, b
console.log(todo.firstAuthor.toUpperCase()) // A
}
但是從內部看,編譯器看不出this.hasAuthors對 有什么影響this.authors。因此,這不會以您想要的方式幫助您。
TypeScript 確實具有用戶定義的型別保護函式和方法的概念,您可以在其中呼叫boolean-returning 函式或方法,它將充當其輸入引數之一(或this方法的背景關系)的型別保護。所以如果hasAuthors是一個方法而不是一個getter,你可以做這樣的事情:
class Todo implements TodoResponse {
userId!: number;
id!: number;
title!: string;
completed!: boolean;
authors?: string[];
constructor(todo: TodoResponse) {
Object.assign(this, todo);
}
hasAuthors(): this is { authors: string[], firstAuthor: string } {
return Boolean(this.authors?.length);
}
get firstAuthor(): string | void {
if (this.hasAuthors()) return this.authors[0] // okay
}
}
通過注釋hasAuthors()as的回傳型別this is { authors: string[], firstAuthor: string },我是說trueof 的結果obj.hasAuthors()會將型別縮小為obj具有已定義string[]屬性(以及已定義firstAuthor屬性)的東西。這在firstAuthor(). 它也適用于課外:
const todo = new Todo({
id: 1, userId: 2, title: "",
completed: false, authors: Math.random() > 0.99 ? undefined : ["a", "b"]
});
if (todo.hasAuthors()) {
// no compiler errors here
console.log(todo.authors.join(", ")) // a, b
console.log(todo.firstAuthor.toUpperCase()) // A
}
所以,那太好了。不幸的是,沒有類似的用戶定義型別保護屬性或訪問器方法功能。在microsoft/TypeScript#43368有一個開放的功能請求,其狀態當前為“等待更多反饋”。這意味著他們可能甚至不會考慮實施這樣的功能,除非他們從社區中聽到一些引人注目的用例。如果你想看到這種情況發生,你可以考慮去那個問題,給它一個??,并解釋為什么這會比當前的選項更好。但是,即使您這樣做了,也無法確定何時或什至是否可以使用此類功能。
所以現在你有點卡住了。要么使用形式的冗余型別保護if (this.authors?.length) return this.authors[0],要么使用型別斷言if (this.hasAuthors) return this.authors![0],或者重構遠離你想要的實作。
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/484014.html
標籤:javascript 打字稿
下一篇:如何獲取包含破折號的所有鍵?
