Javascript 如何确保给定键和值的对象类型的类型安全性?

Javascript 如何确保给定键和值的对象类型的类型安全性?,javascript,flowtype,Javascript,Flowtype,鉴于这一类型: type Obj = $ReadOnly<{| foo: string, bar: number |}>; 但是字符串不能写入条,也不能将数字写入foo。现在,$ElementType定义似乎没有正确地找到与传递的键对应的类型,$ElementType的结果是数字和字符串。这是因为Keys返回所有可能键值的并集,而ElementType返回所有可能值的交集 type Obj = $ReadOnly<{| foo: string, bar: numbe

鉴于这一类型:

type Obj = $ReadOnly<{|
  foo: string,
  bar: number
|}>;

但是
字符串
不能写入
,也不能将
数字
写入
foo
。现在,
$ElementType
定义似乎没有正确地找到与传递的
键对应的类型

$ElementType
的结果是
数字和字符串
。这是因为
Keys
返回所有可能键值的并集,而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';
};

获得所需行为的一种潜在方法是使用泛型。也就是说,看起来

在解决上述问题之前,我认为使用
any
是合理的。它是相对隔离的,不会泄漏到您的功能之外

{
  const setKeyValue = (key: $Keys<Obj>) =>
    (value: $ElementType<Obj, typeof key>) =>
      update(({[key]: value}: any));
};
{
const setKeyValue=(键:$Keys)=>
(值:$ElementType)=>
更新(({[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.
  };
};
{
const setKeyValue=(键:$Keys)=>{
返回{
foo:(value)=>update(({[key]:value})),
bar:(value)=>update(({[key]:value})),
}[key];//在此处使用对象有助于防止您忘记某个字段,或者如果以后添加了某个字段,则流将出错。
};
};
当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);
接口对象{foo:string;bar:number;}
常量更新=(u:Partial)=>(obj:obj):obj=>({…obj,…u});
const setKeyValue=(key:TKey)=>
(value:Obj[TKey])=>update({[key]:{'crazy':'crazy stuff that should error'})
const w:Obj={foo:'hello',bar:5};
setKeyValue('foo')('world')(w);

$ElementType
的结果是
数字和字符串
。这是因为
Keys
返回所有可能键值的并集,而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';
};

获得所需行为的一种潜在方法是使用泛型。也就是说,看起来

在解决上述问题之前,我认为使用
any
是合理的。它是相对隔离的,不会泄漏到您的功能之外

{
  const setKeyValue = (key: $Keys<Obj>) =>
    (value: $ElementType<Obj, typeof key>) =>
      update(({[key]: value}: any));
};
{
const setKeyValue=(键:$Keys)=>
(值:$ElementType)=>
更新(({[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.
  };
};
{
const setKeyValue=(键:$Keys)=>{
返回{
foo:(value)=>update(({[key]:value})),
bar:(value)=>update(({[key]:value})),
}[key];//在此处使用对象有助于防止您忘记某个字段,或者如果以后添加了某个字段,则流将出错。
};
};
当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);
接口对象{foo:string;bar:number;}
常量更新=(u:Partial)=>(obj:obj):obj=>({…obj,…u});
const setKeyValue=(key:TKey)=>
(value:Obj[TKey])=>update({[key]:{'crazy':'crazy stuff that should error'})
const w:Obj={foo:'hello',bar:5};
setKeyValue('foo')('world')(w);

Hm,我本以为我的
setKeyValue
调用是可以静态分析的。为什么不能将
setKeyValue('foo')
中的
key
类型从
$Keys
流到
字符串
?嗯,我原以为我的
setKeyValue
调用是可以静态分析的。为什么不能将
setKeyValue('foo')
中的
键的类型从
$Keys
流到
字符串