我可以使用extends keyof Type推断值的类型

时间:2018-03-16 01:47:16

标签: typescript types

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

下面是相关行旁边有注释的示例代码。

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功能类似的类型?

1 个答案:

答案 0 :(得分:2)

有点疯狂,但我认为能达到你想要的;)它建立在我对你之前关于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的更多信息。

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

干杯, 克里斯