从对象中获取可选的通用值

Get an Optional, Generic, value from an Object

假设我有以下四个对象:

const foo1: Readonly<{foo: number, bar: ?string}> = {
   foo: 123
}

const foo1: Readonly<{foo: number, bar: ?string}> = {
   foo: 123,
   bar: '1123'
}


const bar1: Readonly<{foo2: number, bar2: ?string}> = {
   foo2: 123
}

const foo1: Readonly<{foo: number, bar: ?string}> = {
   foo2: 123,
   bar2: '1123'
}

我现在想将它们转换成 fp-ts Option 形式的承载对象:

{foo: number, bar: Option<string>}

天真的方法是编写两个函数(或者确实内联进行这些计算):

const makeOptional1 = (obj: Readonly<{foo: number, bar: ?string}>) => {
  return (obj.bar === undefined) ? none : some(obj[key]
}

const makeOptional2 = (obj: Readonly<{foo2: number, bar2: ?string}>) => {
  return (obj.bar2 === undefined) ? none : some(obj[key]
}

但是说,我想提取一个更抽象的函数,一个可以接受任意对象和任意键的函数,以及 return 正确的选项。

第一次尝试可能看起来像这样:

const optionalKey = <T, D>(val: D, key: string): Option<T> => {
  if (val[key] === undefined) {
    return none
  } else {
    return some(val[key])
  }
}

编译失败:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'unknown'.
  No index signature with a parameter of type 'string' was found on type 'unknown'.ts(7053)

错误消息非常有道理,但我不知道如何修复它。欢迎任何想法

请看: TS playground

import { Option, some, none } from 'fp-ts/lib/Option';


const foo1: Readonly<{ foo: number, bar?: string }> = {
  foo: 123
}

const foo2: Readonly<{ foo: number, bar?: string }> = {
  foo: 123,
  bar: '1123'
}


const bar1: Readonly<{ foo2: number, bar2?: string }> = {
  foo2: 123
}

const bar2: Readonly<{ foo2: number, bar2?: string }> = {
  foo2: 123,
  bar2: '1123'
}

const makeOptional1 = <T extends Readonly<{ foo: number, bar?: string }>, K extends keyof T>(obj: T, key: K) => {
  return (obj.bar === undefined) ? none : some(obj[key])
}

const makeOptional2 = <T extends Readonly<{ foo2: number, bar2?: string }>, K extends keyof T>(obj: T, key: K) => {
  return (obj.bar2 === undefined) ? none : some(obj[key])
}

type Values<T> = T[keyof T];



const optionalKey = <T, K extends keyof T>(val: T, key: K): Option<Values<T>> => val[key] ? some(val[key]) : none;

const result = optionalKey({ age: 1 }, 'age'); // Option<number>

fp-ts version:2.8.6