typescript - 一種形式的通用約束,形式為「<T 擴展 E>」,其中「E」是「枚舉」?
諸如以下之事的意思是什麼:
function f<T extends E>(obj: T) {}
其中 E 是某個 enum,例如說
enum E {
X
}
由於 enum 實際上無法擴展,是否可以刪除這個限制,並將函數重寫為:
function f(obj: E) {}
附註:這是有問題的程式碼。
答案#1
如果你的函數不需要 T 的類型,那麼你是對的,它不需要是泛型的。
然而,在你提供的檔案中,該類型是在類別內使用的。
這裡是相關部分,其他部分已刪除:
abstract class ComputedEditorOption<K1 extends EditorOption, V> implements IEditorOption<K1, V> {
public readonly id: K1;
constructor(id: K1, deps: EditorOption[] | null = null) {
this.id = id;
//...
}
}
這表示一個類型為 EditorOption 的 id 被傳遞給建構函數。這會被儲存在泛型類型 K1 中。稍後當你訪問 id 屬性時,它將返回傳遞給建構函數的相同枚舉選項。這需要使用泛型以捕捉枚舉的子類型(該枚舉的特定值),並將其用於函數的返回值或類的實例中。
用你自己的例子來說明:
function f1(arg: MyEnum): { id: MyEnum } {
return { id: arg }
}
const a1 = f1(MyEnum.A) // Type: MyEnum
const b1 = f1(MyEnum.B) // Type: MyEnum
當你在這裡將參數輸入為 MyEnum 時,你無法使用回傳類型中提供的枚舉,因此你能做的最好的方法就是將回傳值類型設為 MyEnum,因為你無法知道提供的是該枚舉的哪個值。
但是當你使用泛型時:
function f2<T extends MyEnum>(arg: T): { id: T } {
return { id: arg }
}
const a2 = f2(MyEnum.A) // Type: MyEnum.A
const b2 = f2(MyEnum.B) // Type: MyEnum.B
現在你可以在返回類型中使用完全提供的參數類型。
這或多或少就是你提供的程式碼所做的事情。
遊樂場
答案#2
如果一個型別擴展了一個列舉,這意味著該型別可以是:
- 枚舉的一個特定值
- 枚舉值的某個子集合
- 枚舉的所有可能值
假設我們的列舉有三個值:
enum E {
X,
Y,
Z
}
function f<T extends E>(val: T) {}
當調用函數 f 時,你一次只能傳入一個 E 的值。但這並不意味著泛型 T 只能 是一個 E 的值。如果手動指定泛型 T,以下這些都是有效的:
f<E>(E.X);
f<E.X>(E.X);
f<E.X | E.Y>(E.X);
f<Exclude<E, E.Y>>(E.X);
在每種情況下,E.X 都可以賦值給 T(也就是說,E.X 等於或比 T 更狹窄),並且 T extends E(也就是說,T 等於或比 E 更狹窄)。
遊樂場連結
