将通用枚举类型作为参数传递给 Typescript 中的函数
Passing generic enum type as a parameter to a function in Typescript
我有两个具有相同变体但具有不同字符串值的字符串枚举。
它们被传递给相同的初始函数,该函数接受整个枚举(我认为我可以使用 typeof
,但每个枚举都应该有不同的回调。这似乎是最好的方法输入初始函数?
我的这段代码不起作用,因为它抱怨我不能将 typeof
与我的 T
通用参数一起使用。
enum OpsA {
Start = 'a_start',
Stop = 'a_stop'
}
enum OpsB {
Start = 'b_start',
Stop = 'b_stop'
}
type EitherOps = OpsA | OpsB
function doSomething <T extends EitherOps, U extends typeof T>(action: U, callback: (a: T) => void) {
console.log(action.Start)
callback(action.Start)
console.log(action.Stop)
callback(action.Stop)
}
// does something special for OpsA
const callbackForA = (a: OpsA) => console.log(a)
// does something else special for OpsB
const callbackForB = (b: OpsB) => console.log(b)
doSomething(OpsA, callbackForA)
doSomething(OpsB, callbackForB)
您的问题是 T
是类型而不是值,因此 typeof T
是类别错误。您的困惑可能源于这样一个事实,即 enum
声明将命名值和命名类型都带入范围,并且名称恰好相同。但是,没有一般规则表明同名的值和类型之间有任何关系。
例如,enum OpsA { /* ... */ }
声明值 OpsA
(具有 属性 键 Start
和 Stop
的对象)和类型 OpsA
(枚举对象的 属性 值的 union 类型)。当您将 typeof OpsA
写为类型时,您是在谈论枚举对象的类型,而当您将 OpsA
写为类型时,您是在谈论枚举对象的 属性 值的类型.
但是类型 OpsA
是对象类型 typeof OpsA
的 属性 类型这一事实不能按照您可能尝试做的方式进行概括。没有规则说“给定类型 T
有一个类型 typeof T
其属性是类型 T
”。有关详细信息,请参阅 。
好吧,如果你不会写 U extends typeof T
,你会 做什么?您希望 U
是一个对象类型,其 属性 键是 "Start"
或 "Stop"
。让我们先为这些键获取一个类型。由于 ObjA
和 ObjB
值都有这些键,我们可以将其写为 keyof typeof ObjA
或 keyof typeof ObjB
:
type OpsKeys = keyof typeof OpsA;
// type OpsKeys = "Start" | "Stop"
如果我们想说U
应该是一个对象类型,键为OpsKeys
,值类型为T
,那么我们可以使用the Record<K, V>
utility type:U extends Record<OpsKeys, T>
。像这样:
function doSomething<
T extends EitherOps,
U extends Record<OpsKeys, T>
>(action: U, callback: (a: T) => void) {
console.log(action.Start)
callback(action.Start)
console.log(action.Stop)
callback(action.Stop)
}
现在 doSomething()
内一切正常。让我们确保它也适用于来电者:
doSomething(OpsA, callbackForA) // okay
doSomething(OpsB, callbackForB) // okay
doSomething(OpsA, callbackForB) // error
看起来不错。如果您传入不适合 action
参数的 callback
参数,编译器会发出警告。
我有两个具有相同变体但具有不同字符串值的字符串枚举。
它们被传递给相同的初始函数,该函数接受整个枚举(我认为我可以使用 typeof
,但每个枚举都应该有不同的回调。这似乎是最好的方法输入初始函数?
我的这段代码不起作用,因为它抱怨我不能将 typeof
与我的 T
通用参数一起使用。
enum OpsA {
Start = 'a_start',
Stop = 'a_stop'
}
enum OpsB {
Start = 'b_start',
Stop = 'b_stop'
}
type EitherOps = OpsA | OpsB
function doSomething <T extends EitherOps, U extends typeof T>(action: U, callback: (a: T) => void) {
console.log(action.Start)
callback(action.Start)
console.log(action.Stop)
callback(action.Stop)
}
// does something special for OpsA
const callbackForA = (a: OpsA) => console.log(a)
// does something else special for OpsB
const callbackForB = (b: OpsB) => console.log(b)
doSomething(OpsA, callbackForA)
doSomething(OpsB, callbackForB)
您的问题是 T
是类型而不是值,因此 typeof T
是类别错误。您的困惑可能源于这样一个事实,即 enum
声明将命名值和命名类型都带入范围,并且名称恰好相同。但是,没有一般规则表明同名的值和类型之间有任何关系。
例如,enum OpsA { /* ... */ }
声明值 OpsA
(具有 属性 键 Start
和 Stop
的对象)和类型 OpsA
(枚举对象的 属性 值的 union 类型)。当您将 typeof OpsA
写为类型时,您是在谈论枚举对象的类型,而当您将 OpsA
写为类型时,您是在谈论枚举对象的 属性 值的类型.
但是类型 OpsA
是对象类型 typeof OpsA
的 属性 类型这一事实不能按照您可能尝试做的方式进行概括。没有规则说“给定类型 T
有一个类型 typeof T
其属性是类型 T
”。有关详细信息,请参阅
好吧,如果你不会写 U extends typeof T
,你会 做什么?您希望 U
是一个对象类型,其 属性 键是 "Start"
或 "Stop"
。让我们先为这些键获取一个类型。由于 ObjA
和 ObjB
值都有这些键,我们可以将其写为 keyof typeof ObjA
或 keyof typeof ObjB
:
type OpsKeys = keyof typeof OpsA;
// type OpsKeys = "Start" | "Stop"
如果我们想说U
应该是一个对象类型,键为OpsKeys
,值类型为T
,那么我们可以使用the Record<K, V>
utility type:U extends Record<OpsKeys, T>
。像这样:
function doSomething<
T extends EitherOps,
U extends Record<OpsKeys, T>
>(action: U, callback: (a: T) => void) {
console.log(action.Start)
callback(action.Start)
console.log(action.Stop)
callback(action.Stop)
}
现在 doSomething()
内一切正常。让我们确保它也适用于来电者:
doSomething(OpsA, callbackForA) // okay
doSomething(OpsB, callbackForB) // okay
doSomething(OpsA, callbackForB) // error
看起来不错。如果您传入不适合 action
参数的 callback
参数,编译器会发出警告。