打字稿部分联合类型

时间:2019-11-19 11:46:34

标签: typescript generics

我很难弄清楚如何键入这样的内容:

Fallback

因此,一般而言,此类型采用键FallbackType及其值类型{[key: Fallback]: FallbackType},并创建键值对Partial<FallbackType>和其他值为的键的字典输入const values = { base: { valueA: "baseA", valueB: "baseB", }, context1: { valueA: "context1A", }, context2: { valueB: "context2B", }, }; const useContextValues = <BaseContext extends string, BaseValuesDictionary>( base: BaseContext, values: WithFallback<BaseContext, BaseValuesDictionary>, ): BaseValuesDictionary => { const [activeContext, setContext] = useState<keyof typeof values>(base); const context = { ...values[base], ...values[activeContext] }; return context; };

它的行为应类似于具有后备(base)值及其变体的字典:

base

这样,在baseA上下文中,我们的值应等于baseB中的context1contest1A-在{{ 1}}-baseBcontext2

但是,当我期望baseA返回context2B = useContextValues时,它将解析为:

enter image description here

此外,以这种方式传递值时,它解析为其他类型:

enter image description here

我可以以某种方式解决它吗?或者也许根本不起作用?

1 个答案:

答案 0 :(得分:0)

听起来不错,最好定义类似于对象传播或Merge操作的Object.assign类型:

// Pick own props from T(target) and everything else from U(source, the extending type)
type Merge<T, U> = Omit<T, keyof U> & U

测试:

type T1 = { b: number; a: string }
type S1 = { a: number; c: boolean }

type MergeT1S1 = Merge<T1, S1> // Pick<T1, "b"> & S1
const t: MergeT1S1 = { b: 3, a: 42, c: true } // works
const t2: MergeT1S1 = { b: 3, a: 42 } // error ?
const t3: MergeT1S1 = { b: 3, a: "foo" } // error ?

然后,在Merge顶部定义一个合并的字典类型:

// you also could further restrict D to constraint "extends WithFallback<K, D[K]>"
type MergedDict<K extends keyof D, D> = {
  [P in keyof D]: Merge<D[K], D[P]>
}

...并进行测试:

const values = {
  base: {
    valueA: "baseA",
  },
  context1: {
    valueA: "context1A",
    c: "lala"
  }
}

type MergedDict1 = MergedDict<"base", typeof values>
const m: MergedDict1 = { base: { valueA: "foo" }, context1: { valueA: "bar", c: "lala" } } // OK 
const m2: MergedDict1 = { base: { valueA: "foo" }, context1: { valueA: "bar" } } // error ?
const m3: MergedDict1 = { base: { valueA: "foo" }, context1: { c: "lala" } } // error ?

最后一步只是调整功能签名useContextValues

// set WithFallback as a constraint, not as a type itself for values
declare const useContextValues: <K extends keyof D,
  D extends WithFallback<K, D[K]>>(
  base: K,
  values: D,
) => MergedDict<K, D>

const res = useContextValues("base", values) // should work like above

Playground

关于您的错误:WithFallback中,您确实为键fallback定义了类型变量{ [fallback in Fallback]: FallbackType },但是没有使用它来访问属性值。因此TS形成了values所有可能的prop值的并集类型(如屏幕截图所示)。

为了更正此问题,我们在函数useContextValues中还将WithFallback用作类型约束,而不是values的类型。 WithFallback<K, D[K]>的意思是,我们传入了像K这样的基本键"base"和像D[K]这样的FallbackType { valueA: "baseA", valueB: "baseB" },并且得到了可以定义其他键的基本字典类型(context1等),其值符合FallbackType。