打字稿为嵌套的可选对象类型创建默认值

时间:2021-04-01 19:19:10

标签: typescript

我有一个类型 MyType

type MyType = {
  a?: {c: string},
  b?: {e: string},
}

包含可选的嵌套对象。我想创建一个函数 getDefaultValue,它接受​​ K 的键 MyType 并返回由键 K 指定的嵌套对象的默认表示。

function getDefaultValue<K extends keyof MyType>(key: K):Required<MyType>[K] {
  if (key === 'a') return {c: 'hello'}
  return {e: 'hello'}
}

const variable: Required<MyType>['a'] = getDefaultValue('a')

我收到以下打字稿错误:

TS2322: Type '{ c: string; }' is not assignable to type 'Required<MyType>[K]'.
  Type '{ c: string; }' is not assignable to type '{ c: string; } & { e: string; }'.
    Property 'e' is missing in type '{ c: string; }' but required in type '{ e: string; }'.
TS2322: Type '{ e: string; }' is not assignable to type 'Required<MyType>[K]'.
  Type '{ e: string; }' is not assignable to type '{ c: string; } & { e: string; }'.
    Property 'c' is missing in type '{ e: string; }' but required in type '{ c: string; }'.

2 个答案:

答案 0 :(得分:2)

将返回值的类型与泛型参数匹配可能有点棘手,但在这种情况下,您可以通过将默认值放在对象中来完全避免这个问题

const defaults = {
  a: { c: 'hello' },
  b: { e: 'hello' },
}

并像这样声明 getDefaultValue

function getDefaultValue<K extends keyof MyType>(key: K) {
  return defaults[key]
}

const test1 = getDefaultValue('a') // inferred type: {c: string}
const test2 = getDefaultValue('b') // inferred type: {e: string}

缺少默认值将通过 defaults[key] 处的类型错误发出信号。

TypeScript playground

答案 1 :(得分:0)

我认为使用 TypeScript 是不可能的,因为您正在尝试使用运行时值而不是类型来创建泛型。

请考虑以下示例并尝试回答问题:

const key: 'a' | 'b' = 'a';
const variable: Required<MyType>['a'] = getDefaultValue(key)
  1. 如何保证结果类型基本上是Required<MyType>['a']而不是Required<MyType>['b']
  2. 打字稿应该如何理解 K extends keyof MyType 是一个值的类型?

附言作为一个 hack,你可以指定 any 作为返回类型,但这不是你需要用 TypeScript 做的事情

type MyType = {
  a?: {c: string},
  b?: {e: string},
}

type MyKeys = keyof MyType;

function getDefaultValue(key: MyKeys): any {
  if (key === 'a') {
    return {c: 'hello'};
  }
  return {e: 'hello'}
}

const variable: Required<MyType>['a'] = getDefaultValue('a')

P.P.S.我建议创建一个函数,该函数将返回整个对象的默认值,然后简单地获取您需要的内容

function getDefaultValue(): Required<MyType> {
  return {
    a: {c: 'hello'},
    b: {e: 'hello'},
  };
}
const variable = getDefaultValue().a;