Typescript接口,用于基于键值约束对象

时间:2019-11-12 07:27:58

标签: typescript react-redux

我是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'

两部分问题:

  1. 是否有可能在value中优化PayloadType,以使test.value的类型为boolean,如果test.key == "bool"的类型为{ {1}}是否为number?我尝试了test.key === "num",但并没有足够的约束:(

  2. 是否可以使分配value: StoreType[keyof StoreType]类型安全且无错误?我已经看到https://github.com/microsoft/TypeScript/issues/31663中的错误,但是我不确定该如何进行,也不知道这是否与问题1有关。

如果我错过了一些基本知识,我不会感到惊讶。

谢谢!

2 个答案:

答案 0 :(得分:3)

key中将PayloadType类型定义为具有K约束的通用类型参数keyof StoreType将达到目的:

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"。在"bool" | "num"中对StoreType的查找将解析为这些键的所有可能的返回类型number | boolean

通过将key类型与K一起声明为泛型类型参数PayloadType<"bool">,表示您希望使用特定的密钥StoreType(不是联合)。

Playground

答案 1 :(得分:1)

@ 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});

有效负载也可以是主要类型,如上例中通过get_user操作所看到的。这种方法是类型安全的,您不能使用错误的有效负载类型发送get_user操作。希望对您有所帮助。