我有以下情況:
class Dispatcher<R extends (...args: any) => any, T = undefined> {
fn: R
extra: T
constructor(fn: R, extra?: T) {
this.fn = fn;
this.extra = extra;
}
}
const test = new Dispatcher(() => {
return true;
});
// TS type hinting should know that extra is undefined
test.extra;
const test2 = new Dispatcher(() => {
return true;
}, {
graphUrl: "/foo/"
});
// TS type hinting should know that extra exists and has a property graphUrl
test2.extra.graphUrl
在這種情況下,我希望extra類成員根據它是否傳遞給建構式進行推斷。如果我傳遞一個布林值,它應該是一個布林值,如果我傳遞一個字串,它應該是一個字串,如果我傳遞一個未定義的,它應該是未定義的。現在推理作業extra正常并且型別正確,但是當我分配 TS 時,TS 在建構式代碼中引發錯誤this.extra = extra。嚴格來說,這個錯誤是有道理的,因為我將一個可以未定義的型別分配給一個不能定義的型別。問題是,如果我將成員定義更新為,extra?: T那么推理就會中斷,因為現在它認為 extra 類似于string | undefined,這是不正確的。問題是額外的變數實際上不是“可選的”,它是傳遞的值,該值可能未定義......這與可選不同。
Type 'T | undefined' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'T | undefined'.
如果我修復了建構式代碼中的錯誤,那么型別推斷就會停止作業,并且我會得到一些string | undefined不準確的東西。我們知道型別,因為它已傳遞給建構式。
游樂場鏈接
uj5u.com熱心網友回復:
不幸的是,泛型型別并不總是被推斷出來的。有時它們是明確的。所以打字稿保護你免受這樣的情況:
new Dispatcher<() => boolean, string>(() => true)
現在根據您的類的型別,這是實體化類的有效方法。但是在內部,當它應該是extra一個.undefinedstring
我不完全確定如何在沒有型別斷言的情況下解決此問題,但您至少可以確保執行型別斷言是安全的。
如果T未定義,我們需要做的是使引數可選。您可以通過使函式引數成為決議為元組的條件型別來做到這一點。
class Dispatcher<R extends (...args: any) => any, T = undefined> {
fn: R
extra: T
constructor(...args: T extends undefined ? [fn: R] : [fn: R, extra: T]) {
const [fn, extra] = args
this.fn = fn;
this.extra = extra as T; // as T is still needed, sadly.
}
}
現在如果T未定義,則引數元組中缺少引數。否則,extra是必需的,并且需要是 type T。
上面沒有錯誤的情況下,現在是一個錯誤:
new Dispatcher<() => boolean, string>(() => true) // Expected 2 arguments, but got 1.(2554)
這里因為Tis string,那么第二個引數是必需的。
但這些仍然按預期作業:
new Dispatcher<() => boolean>(() => true) // fine
new Dispatcher<() => boolean, undefined>(() => true) // fine
new Dispatcher<() => boolean, string>(() => true, 'foobar') // fine
Typescript 仍然對extra可以安全分配感到困惑,我不確定如何解決這個問題。但至少現在我相信將不受支持的型別放入 是不可能的extra,所以as T應該是安全的。
操場
不過,可能還有更好的解決方案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/494535.html
上一篇:在Go中列印型別引數名稱
下一篇:C#如何獲取泛型型別屬性
