我是打字稿的新手,并且有一个关于它的问题,我似乎无法以可谷歌的方式构成。
假设我定义了这个接口:
interface MyInterface {
myField: "myValue"
}
我希望能够编写这行代码:
const value = MyInterface.myField; // expect value to equal "myValue"
这不编译,但我想知道是否有某种方法来实现这种行为。由于myField的值是在typescript编译时定义的,我相信这应该是可能的。但我无法弄清楚该怎么做。
任何建议表示赞赏谢谢!
更新:
我想我需要提供更多信息。我正在尝试通过以下文章减少样板并在redux应用程序中维护类型安全性:
https://medium.com/@resir014/a-type-safe-approach-to-redux-stores-in-typescript-6474e012b81e
我也在使用redux-saga,基本上我正在尝试创建一个类型安全的takeEvery。
假设我将两个操作定义为接口,如上文所述:
import { Action } from 'redux'
interface MyActionA extends Action {
typeString: "MyActionA",
payload: {
// omitted
}
}
interface MyActionB extends Action {
typeString: "MyActionB",
payload: {
// omitted
}
}
type MyActionBase =
| MyActionA
| MyActionB
是否有一些有效的方法来写下面的内容?:
function* typeSafeTakeEvery<ActionType extends MyActionBase>(saga: Function) {
const typeString = ActionType.typeString; // <-- I don't know how to write this line
yield takeEvery(typeString, function*(action: ActionType) {
yield saga(action);
});
}
对于此泛型函数的任何给定实例化,它知道ActionType的静态类型(MyActionA或MyActionB),并且它必须具有“typeString”字段,其类型为“MyActionA”或“MyActionB”。我想将此“type”用作常量值,并将其传递给实际的takeEvery函数。
我离基地不远吗?
要定义值'myValue'
而不是类型'myValue'
,您可以使用enum
而不是interface
:
enum MyEnum {
myField = "myValue"
}
const value = MyEnum.myField;
不编译的原因是因为ActionType
是所谓的类型参数,它是传递给<...>
而不是(...)
的任何东西,它们被称为值参数,或者更简单地说,只是参数。
因为它是一个类型而不是值,所以TypeScript会从编译的JavaScript输出中删除它的定义,这就是为什么你会得到一个错误,它被用作一个值,即使它是一个类型。因此,当编译器运行时,它会留下未定义的ActionType
引用,该引用未在JavaScript中的任何位置声明。
现在,为了解决你的问题,我仍然建议使用enum
,并传递actionType
作为值参数,让ActionType
类型参数推断其类型并使用它来声明扩展MyAction
的本地类型MyActionBase
,从而隐式地选择MyActionA
或MyActionB
在字符串文字传递。
import { Action } from 'redux'
enum MyActionType {
MyActionA = 'MyActionA',
MyActionB = 'MyActionB'
}
interface MyActionA extends Action {
typeString: MyActionType.MyActionA,
payload: {
// omitted
}
}
interface MyActionB extends Action {
typeString: MyActionType.MyActionB,
payload: {
// omitted
}
}
type MyActionBase =
| MyActionA
| MyActionB
function* typeSafeTakeEvery<ActionType extends MyActionType>(actionType: ActionType, saga: Function) {
type MyAction = MyActionBase & { typeString: ActionType }
yield takeEvery(actionType, function*(action: MyAction) {
yield saga(action);
});
}
// Usage
typeSafeTakeEvery(MyActionType.MyActionA, ...)