打字稿游樂場
我使用d3來自@types/d3. 我有一種方法可以結合選擇和轉換進行操作。爭論可能是其中之一。Selection 和 Transition 型別都有selectAll方法。但是當我嘗試申請selectAll工會時,我收到以下錯誤:
此運算式不可呼叫。聯合型別的每個成員'{():Selection<null, undefined, BaseType, unknown>; (selector: null): 選擇<null, undefined, BaseType, unknown>; (選擇器:未定義):選擇<...>;<DescElement extends BaseType, OldDatum>(selector: string): Selection<...>; <DescElement extends BaseType, OldDatum>(selector: ValueFn<...>): Selection<...>; } ...' 有簽名,但這些簽名都不兼容。
這是給出此錯誤的代碼示例:
/* Definitions from @types/d3 */
export type BaseType = Element | Document | Window | null;
export type ValueFn<T extends BaseType, Datum, Result> = (this: T, datum: Datum, index: number, groups: T[] | ArrayLike<T>) => Result;
export interface Transition<GElement extends BaseType, Datum, PElement extends BaseType, PDatum> {
selectAll<DescElement extends BaseType, OldDatum>(selector: string): Transition<DescElement, OldDatum, GElement, Datum>;
selectAll<DescElement extends BaseType, OldDatum>(selector: ValueFn<GElement, Datum, DescElement[] | ArrayLike<DescElement>>): Transition<DescElement, OldDatum, GElement, Datum>;
}
export interface Selection<GElement extends BaseType, Datum, PElement extends BaseType, PDatum> {
selectAll(): Selection<null, undefined, GElement, Datum>;
selectAll(selector: null): Selection<null, undefined, GElement, Datum>;
selectAll(selector: undefined): Selection<null, undefined, GElement, Datum>;
selectAll<DescElement extends BaseType, OldDatum>(selector: string): Selection<DescElement, OldDatum, GElement, Datum>;
selectAll<DescElement extends BaseType, OldDatum>(selector: ValueFn<GElement, Datum, DescElement[] | ArrayLike<DescElement>>): Selection<DescElement, OldDatum, GElement, Datum>;
}
/* My code */
function myFunc(maybeTransition: Selection<BaseType, unknown, BaseType, unknown> | Transition<BaseType, unknown, BaseType, unknown>) {
const texts = maybeTransition.selectAll('text'); // ERROR: This expression is not callable.
// do something with texts
}
所以問題是:
- 是否可以使用現有的型別定義來解決此問題?
- 如果在不更改過渡或選擇界面的情況下無法解決問題,應該如何解決?
uj5u.com熱心網友回復:
對于您的函式的引數maybeTransition,您正在指定一個聯合型別,期望它完全是這兩種型別的聯合:
Selection<BaseType, unknown, BaseType, unknown> | Transition<BaseType, unknown, BaseType, unknown>
不幸的是,完全違反直覺,聯合型別的行為與您的預期完全不同!檔案告訴我們
聯合型別是由兩種或多種其他型別組成的型別,表示可能是這些型別中的任何一種的值。
到現在為止還挺好。但是,當涉及到聯合型別的屬性時
TypeScript 只有在對聯合體的每個成員都有效的情況下才允許操作。
如果您將介面/型別視為一組屬性,從數學上講,這將是一個交集而不是一個聯合。我一直認為這是用詞不當。小字體檔案也解決了一個事實:
型別的聯合似乎具有這些型別的屬性的交集,這可能會令人困惑。這不是偶然的——聯合這個名字來源于型別論。聯合
number | string是通過取每種型別的值的聯合組成的。請注意,給定兩個具有關于每個集合的相應事實的集合,只有這些事實的交集適用于集合本身的并集。例如,如果我們有一個房間里有戴帽子的高個子,而另一個房間里有講西班牙語的人戴帽子,在組合這些房間后,我們對每個人的唯一了解就是他們必須戴帽子。
查看 for 的型別定義Selection,Transition您會注意到在這兩種型別中都沒有兼容的方法,從而使您得到一個完全沒有屬性的空型別。因此,無法在該空型別上呼叫方法.selectAll(),這基本上就是錯誤訊息告訴您的內容。
有兩種解決方法:
使用交叉點型別。您可以將型別定義修改為
Selection<BaseType, unknown, BaseType, unknown> & Transition<BaseType, unknown, BaseType, unknown>
盡管這可行,但我不鼓勵使用,因為您將兩個不同的界面混合為一種型別以“使其正常作業”。您沒有擴展介面,也沒有豐富它,而只是混合了.selectAll()方法的多載定義,這感覺有些粗略。
- 縮小你的打字范圍。最好,您應該繼續使用聯合型別,并在使用它時將型別縮小到 a
Selection或 a 。Transition這可以通過使用instanceof型別保護來完成。這樣一來,TypeScript 就能夠區分這兩種型別:
import { Selection, selection, Transition, transition, BaseType } from "d3";
function myFunc(
maybeTransition: Selection<BaseType, unknown, BaseType, unknown> |
Transition<BaseType, unknown, BaseType, unknown>
) {
let texts;
if (maybeTransition instanceof selection) { // type guard
texts = maybeTransition.selectAll("text"); // texts is of type Selection
} else if (maybeTransition instanceof transition) { // type guard
texts = maybeTransition.selectAll("text"); // texts is of type Transition
}
}
這可能看起來很笨拙,但這是因為 TypeScript 本身的型別安全。盡管在 Vanilla JavaScript 中兩者都Selection被Transition建模為相似,但 TypeScript 的型別安全有時是以更冗長的代碼為代價的。
您還必須記住,以上所有內容都適用于texts變數,它也是兩種型別的聯合。稍后您將不得不在代碼中以相同的方式處理該問題。不過,根據您的整體設計,可能值得考慮一種完全不同的方法。
uj5u.com熱心網友回復:
問題是這兩種方法的型別不兼容,你需要區分它們。工會可以解決:
function myFunc(param: { type: 'Selection', selection: Selection<BaseType, unknown, BaseType, unknown> } | { type: 'Transition', transition: Transition<BaseType, unknown, BaseType, unknown> }) {
if (param.type === 'Selection') {
const texts = param.selection.selectAll('text');
} else {
const texts = param.transition.selectAll('text');
}
// do something with texts
}
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/422077.html
標籤:
