typescript 在创建对象时,从对象数组推断字符串的并集

4ioopgfo  于 2023-06-24  发布在  TypeScript
关注(0)|答案(1)|浏览(172)

假设我有以下接口:

interface Item {
  id: string;
  name: string;
}

interface Foo {
  items: Item[];
  defaultItem: Foo[number]['id']
}

如果我有以下代码,我希望defaultItem只是items中设置的id键之一,如下所示:

const myObj: Foo = {
  items: [{ id: 'bar', name: 'Bar' }, { id: 'baz', name: 'Baz'} ],
  defaultItem: 'fooooo' // error, can only be 'bar' and 'baz'
}

这是在打字吗?
我所尝试的:
1.在我的真实的实现中,Foo看起来像这样:

interface Foo<TItems extends Item[]> {
  items: TItems;
  defaultItem: TItems[number]['id']
}

这最终推断出string
1.在myObj中,我将as const添加到数组items中。没成功
我有什么选择?

axr492tv

axr492tv1#

对于Typescript版本>= 5.0.0,我们将使用在5.0.0中引入的const类型参数。基本上,它做的事情和const assertion做的事情一样。
由于const assertionconst type parameters都将数组转换为readonly,因此我们也需要更新extends的条件,此外,您提到接口将用作react组件 prop ,因此以下代码将在react上下文中:

interface Foo<TItems extends readonly Item[]> {
  items: TItems;
  defaultItem: TItems[number]['id'];
}

const Comp = <const T extends readonly Item[]>(props: Foo<T>) => {
  return null;
};

测试:

const Wrapper = () => (
  <Comp
    items={
      [
        { id: 'bar', name: 'Bar' },
        { id: 'baz', name: 'Baz' },
      ]
    }
    defaultItem="fooo" // expected error
  />
);

对于typescript版本< 5.0.0,只需一个const assertion即可,因为我们更新了extends条件:

const Comp = <T extends readonly Item[]>(props: Foo<T>) => {
  return null;
};

const Wrapper = () => (
  <Comp
    items={
      [
        { id: 'bar', name: 'Bar' },
        { id: 'baz', name: 'Baz' },
      ] as const
    }
    defaultItem="fooo" // expected error
  />
);

Playground

相关问题