【问题标题】:Can I infer the type of a value using extends keyof Type我可以使用 extends keyof Type 推断值的类型吗
【发布时间】:2018-08-25 00:05:52
【问题描述】:

previous question 中,我询问了如何分配对象的值和对象的键。现在我已经实现了它,第一个函数在使用keyof 时工作正常,但第二个函数不允许我打开key 来缩小类型。

以下是相关行旁边有 cmets 的示例代码。

type JWT = { id: string, token: string, expire: Date };
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) };


function print(key: keyof JWT) {
    switch (key) {
        case 'id':
        case 'token':
            console.log(obj[key].toUpperCase());
            break;
        case 'expire':
            console.log(obj[key].toISOString()); // Works!
            break;
    }
}

function onChange<K extends keyof JWT>(key: K, value: JWT[K]) {
    switch (key) {
        case 'id':
        case 'token':
            obj[key] = value + ' (assigned)';
            break;
        case 'expire':
            obj[key] = value.toISOString(); // Error!
            break;
    }
}

如何实现onChange 函数,以便开关缩小类似于上面print 函数的类型?

【问题讨论】:

  • 这是一个design limitation,TypeScript 只缩小了切换的key 的类型,而不是Kvalue 的相关类型。简短的回答可能是在这种情况下您只需要断言(value as Date).toISOString()
  • 嗯,当然,obj[key] 应该是 Date 而不是 string 在这种情况下无论如何。

标签: typescript types


【解决方案1】:

有点疯狂,但我认为实现了您的愿望;)它建立在我对您之前关于valueof 的问题的回答之上。它还将onChange 签名更改为接受{key: K extends string, value: JWT[K]} 类型的对象,而不是单独的keyvalue 参数

type JWT = { id: string; token: string; expire: Date }
const obj: JWT = { id: 'abc123', token: 'tk01', expire: new Date(2018, 2, 14) }

function print(key: keyof JWT) {
  switch (key) {
    case 'id':
    case 'token':
      console.log(obj[key].toUpperCase())
      break
    case 'expire':
      console.log(obj[key].toISOString()) // Works!
      break
    default:
      return
  }
}

type ObjectToUnion<
  T extends object,
  U = { [K in keyof T]: { key: K; value: T[K] } }
> = U[keyof U]

function onChange(jwt: ObjectToUnion<JWT>) {
  switch (jwt.key) {
    case 'id': // Try to comment this line and see the error appear at 'exhaustiveCheck'
    case 'token':
      obj[jwt.key] = jwt.value + ' (assigned)'
      return
    case 'expire':
      obj[jwt.key] = jwt.value.toISOString() // Error!
      return
    default:
      // Optionally add exhaustive check to make sure you have covered all cases :)
      const exhaustiveCheck: never = jwt
      return
  }
}

您可以阅读有关永不输入here 的更多信息。

我希望能回答你的问题:)

干杯, 克里斯

【讨论】:

  • 哇,这太聪明了!我特别喜欢exhaustiveCheck,如果其中一个案例丢失,就会出错!我想唯一的区别是对onChange('id', 'def456') 的调用需要重构为使用onChange({ key: 'id', value: 'def456' })
猜你喜欢
  • 1970-01-01
  • 2013-10-18
  • 2018-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多