【问题标题】:Is it possible for TS to now the type of the second param of a function based on the type of the first oneTS 现在是否可以根据第一个参数的类型来确定函数的第二个参数的类型
【发布时间】:2021-05-20 21:46:49
【问题描述】:

我正在努力简化我们的 redux 设置,我想知道是否可以这样做:

type Action = {type: "foo", payload: string} | {type: "bar", payload: number} | {type: "baz"}

function Test<T extends Action>(action: T['type'], payload?: T['payload']) {
    return
}

Test("foo", "string")
Test("bar", 1337)
Test("baz")

我们的想法是,如果您键入“foo”作为第一个参数,则应该只允许字符串作为第二个参数,“bar”只有数字,“baz”作为第一个参数应该能够将第二个参数留空。

【问题讨论】:

  • 有点遗漏这个问题的“真正主题”,但我真的可以推荐你查看官方的 Redux Toolkit,因为它真的面向 TypeScript,你不会编写动作类型之类的东西(既不是字符串也不是打字稿类型),也不再是手动的动作创建者。
  • 同样缺少“真正的主题”,但还有typesafe-actions,它为您做了很多工作
  • 确实和redux没关系。基于函数的第一个参数,我希望 TS 知道第二个参数的类型。

标签: typescript


【解决方案1】:

有点复杂的解决方案,但它有效

interface ActionWithPayloadDefinition {
    foo: string,
    bar: number
    complex: {
        name: string
        age: number
    }
}
type ActionWithPayloadName = keyof ActionWithPayloadDefinition
type ActionWithoutPayloadName = 'baz'

// Use function overload: https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
function Test<T extends ActionWithoutPayloadName>(type: T): void
function Test<T extends ActionWithPayloadName>(type: T, payload: ActionWithPayloadDefinition[T]): void
function Test(type: string, payload?: any){
    // Do something
}

Test("foo", "string")
Test("bar", 1337)
Test("baz")
Test("complex", { name: 'testing', age: 999 })

我介绍了一个ActionWithPayloadDefinition 接口,我们用它来将动作的名称映射到有效负载的类型。我在这里添加了一个complex 类型来证明我们可以拥有更复杂的payload。

Test函数中,我们没有使用完整的Action作为泛型参数,而是仅使用动作名称作为泛型参数。这允许我们使用该参数将其映射回预期的有效负载类型。

Playground link

【讨论】:

  • 这正是我想要的 :) 谢谢!
猜你喜欢
  • 1970-01-01
  • 2023-02-13
  • 2020-10-21
  • 2019-11-25
  • 1970-01-01
  • 2022-10-04
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
相关资源
最近更新 更多