Результат $ElementType<Obj, typeof key>
равен number & string
. Это связано с тем, что Keys<Obj>
возвращает объединение всех возможных значений ключа, а ElementType, который возвращает пересечение всех возможных значений.
type Obj = $ReadOnly<{| foo: string, bar: number |}>;
{
let k: 'foo' = 'foo';
// Works because Flow knows `k` is exactly `foo` and its value can only be a string.
let v: $ElementType<Obj, typeof k> = 'wow';
};
{
let k: $Keys<Obj> = 'foo';
// ERROR: Flow can't know `typeof k` is exactly `foo` and not also `bar`.
let v: $ElementType<Obj, typeof k> = 'wow';
};
пробный поток
number & string
не очень полезен:
// Cannot assign `'wow'` to `a` because string [1] is incompatible with number [2].
let a: number & string = 'wow';
// Cannot assign `10` to `b` because number [1] is incompatible with string [2].
let b: number & string = 10;
[попытка выполнения]
Один из возможных способов получить желаемое поведение - с помощью дженериков. Тем не менее, похоже, что ElementType еще не работает должным образом с Generics
Пока вышеприведенное не будет выполнено, я думаю, что это разумный случай для использования any
. Он относительно изолирован и не вытекает за пределы вашей функции.
{
const setKeyValue = (key: $Keys<Obj>) =>
(value: $ElementType<Obj, typeof key>) =>
update(({[key]: value}: any));
};
Как упомянуто в билете, есть способы сделать это в безопасном месте, которые Flow поймет, но они более многословны.
{
const setKeyValue = (key: $Keys<Obj>) => {
return {
foo: (value) => update(({[key]: value})),
bar: (value) => update(({[key]: value})),
}[key]; // using an object here is helpful in case you forget a field or if one is added later, Flow will error.
};
};
Когда Flow не уверен в чем-то, он обычно выдает ошибку. TypeScript обычно будет молчать, если не уверен.
т. Е. Следующая ошибка не возникает в TypeScript, но должна.
interface Obj { foo: string; bar: number; }
const update = (u: Partial<Obj>) => (obj: Obj): Obj => ({...obj, ...u});
const setKeyValue = <TKey extends keyof Obj>(key: TKey) =>
(value: Obj[TKey]) => update({[key]: {'crazy': 'crazy stuff that should error'}})
const w: Obj = {foo: 'hello', bar: 5};
setKeyValue('foo')('world')(w);
[Игровая площадка TypeScript]