打字稿验证所有对象值,同时提取键作为并集

时间:2020-03-10 17:52:06

标签: typescript interface

我正在尝试验证对象文字的值,同时创建所有键的并集作为函数的参数类型。

interface PathValue {
    prop1: string;
    prop2?: number;
}

interface PathDeclaration {
    [key: string]: PathValue;
}

const allPaths: PathDeclaration = {
    'one': {prop1: 'foo'},
    'two': {prop1: 'bar', prop2: 2},
}


function getItem(path: Extract<keyof typeof allPaths, string>) {
    return allPaths[path];
}

此示例的问题在于,由于PathDeclaration是allPath的类型,并且其键只是通用字符串,因此我的path参数无法再从对象文字中推断出键。

我能想到的唯一解决方案是必须在单独的接口中声明所有键(重复代码),或者代替键入allPaths,我可以删除PathDeclaration并仅键入{{1 }}都不是非常优雅的解决方案。有没有办法验证整个'one': <PathValue> {prop1: 'foo'},对象并从对象文字创建键联合类型?

1 个答案:

答案 0 :(得分:1)

您要使用通用函数将const allPaths初始化为1)将type constraint PathDeclaration 进行添加2)让TS infer为给定值对象文字类型自动生成。只有函数可以一步完成此操作。

const createPaths = <T extends PathDeclaration>(pd: T) => pd

const allPaths = createPaths({
  'one': { prop1: 'foo' },
  'two': { prop1: 'bar', prop2: 2 },
})
/* 
{
  one: { prop1: string; };
  two: { prop1: string; prop2: number; };
}
 */

以上将捕获错误:

const allPathsError = createPaths({
  'one': { prop3: 'foo' }, // error
  'two': { prop1: 'bar', prop2: "bar" }, // error
})

并推断所有键:

// path: "one" | "two"
function getItem(path: Extract<keyof typeof allPathsInline, string>) {
  return allPathsInline[path];
}

这也是我喜欢使用IIFE使事情变得苗条的少数情况之一:

const allPathsInline = (<T extends PathDeclaration>(pd: T) => pd)({
  'one': { prop1: 'foo' },
  'two': { prop1: 'bar', prop2: 2 },
})

Code sample