我是Typescript的新手,一直在玩。我有这样的代码,它得到了一个错误(为了简单起见,减少了(。它最终是为了一个redux动作/减速器,这就是为什么它有点复杂的原因。
interface StoreType {
bool: boolean,
num: number,
}
interface PayloadType {
key: keyof StoreType,
value: ???
}
let test: PayloadType = {
key: "bool",
value: 3 // should ideally fail if value is not a boolean
}
var obj: StoreType = { bool: true, num: 3 }
obj[test.key] = test.value // ts(2322) Type 'number' is not assignable to type 'never'
由两部分组成的问题:
是否有可能在
PayloadType
中细化value
,使得如果test.key == "bool"
,则test.value
为boolean
类型,如果test.key === "num"
,则为number
类型?我尝试了value: StoreType[keyof StoreType]
,但没有足够的约束:(有没有一种方法可以使分配
obj[test.key] = test.value
类型安全且无错误?我在中看到了错误https://github.com/microsoft/TypeScript/issues/31663,但我不确定如何继续,我不知道这是否与问题1有关。
如果我错过了一些基本的东西,我不会感到惊讶。
谢谢!
将PayloadType
中的key
类型定义为具有keyof StoreType
约束的泛型类型参数K
即可:
interface PayloadType<K extends keyof StoreType> {
key: K,
value: StoreType[K]
}
let test: PayloadType<"bool"> = {
key: "bool",
value: true // ✅
}
let testError: PayloadType<"bool"> = {
key: "bool",
value: 3 // 💣
}
var obj: StoreType = { bool: true, num: 3 }
obj[test.key] = test.value
StoreType[keyof StoreType]
不适用于本例,因为keyof StoreType
解析为并集类型"bool" | "num"
。并且在StoreType
中查找"bool" | "num"
将解析为这些密钥的所有可能的返回类型number | boolean
。
通过将key
类型与PayloadType<"bool">
一起声明为泛型类型参数K
,可以表示需要StoreType
的specifc键(而不是并集(。
游乐场
@ford04看起来是你所问问题的一个很好的答案,但不是你真正想要实现的事情。
没有理由(或者我看不出(在您的负载中有明确的类型信息。我想说,你揭示了一些技术细节的领域数据应该披露。所以对我来说,这是错误的做法。
这样的意义是以领域信息的形式进行判别:
type ActionType = 'add_user' | 'get_user' | 'add_comment' | 'get_comment' // example action types
// type constructor to save us typing
type Action<T extends ActionType, P> = {
type: T,
payload: P
}
// specific actions
type UserId = number; // just for convenience and readability
type GetUserAction = Action<'get_user', UserId>
type User = {name: string} // example payload type
type AddUserAction = Action<'add_user', User>
// action creator
const getUser = (id: UserId):GetUserAction => ({type: 'get_user', payload: id});
Payload也可以是主要类型,正如您在上面的get_user
操作示例中看到的那样。这种方法是类型安全的,不能用错误的有效负载类型发送get_user
操作。希望能有所帮助。