如何从嵌套对象获取类型

时间:2019-11-18 19:55:06

标签: typescript

我想创建一个识别嵌套对象的字符串的类型。但是,尝试这样做只会给我返回类型string而不是特定字符串数组。实施此方法的正确方法是什么?请参见下面的代码。谢谢!

interface SampleInterface {
  allIds: string[];
  byId: {
    [key: string]: string[];
  };
}

const sampleObject: SampleInterface = {
  allIds: [
    'foo',
    'bar',
    'alpha',
    'bravo',
    'charlie',
  ],
  byId: {
    foo: ['hello world'],
    bar: ['hello world'],
    alpha: ['hello world'],
    bravo: ['hello world'],
    charlie: ['hello world'],
  },
};

type ObjectKeys = keyof typeof sampleObject.byId;
// desired: type ObjectKeys = 'foo' | 'bar' | 'alpha' | 'bravo' | 'charlie';
// actual: type ObjectKeys = string;

const fn = (x: ObjectKeys) => console.log(x);

fn('test'); // no error is returned

1 个答案:

答案 0 :(得分:2)

sampleObject的类型为SampleInterface,因为这是您为其提供的类型注释。因此sampleObject.byId的类型为{ [key: string]: string[] },因为这是您定义接口的方式。因此keyof typeof sampleObject.byIdstring

直接的解决方案是声明sampleObject而不使用类型注释,从而使编译器尽可能具体地推断其类型。

也就是说,最好也将SampleInterface设为通用,以便类型检查器强制allIds中的字符串与byId的属性名称相同。如果要让常量的类型使用SampleInterface,则无需重复代码的最佳方法是首先声明byId对象,根据该对象的键声明ObjectKeys类型,然后然后使用Object.keys()动态创建allIds数组。

interface SampleInterface<K extends PropertyKey> {
  allIds: K[];
  byId: Record<K, string[]>
}

const _sampleObjectById = {
  foo: ['hello world'],
  bar: ['hello world'],
  alpha: ['hello world'],
  bravo: ['hello world'],
  charlie: ['hello world'],
};

// ObjectKeys = 'foo' | 'bar' | 'alpha' | 'bravo' | 'charlie'
type ObjectKeys = keyof typeof _sampleObjectById;

const sampleObject: SampleInterface<ObjectKeys> = {
  allIds: Object.keys(_sampleObjectById) as ObjectKeys[],
  byId: _sampleObjectById
}

// logs ['foo', 'bar', 'alpha', 'bravo', 'charlie']
console.log(sampleObject.allIds);

Playground Link