如何在TypeScript中为具有一个不同键的对象声明类型

5

你好,我想创建一个像这样的对象类型:

const z = {
    name: { // this one is special
        buty: ['qqqq']
    },
    lipa: ['xxx'],
    // more keys here
};

基本上,它就像这样一个对象

type Test = {
    [key: string]: string[]
}

除了一个小例外,它总是有一个键名称和稍微不同的值。

type Special = {
    name: {
        [key: string]: string[]
    }
}

但是当我尝试合并这两种类型时

type Test =
    { [key: string]: string[] } &
    { name: { [key: string]: string[] } };

const z: Test = {
    name: { // this one is special
        buty: ['qqqq']
    },
    lipa: ['xxx'],
    // more keys here
};

我遇到了一个错误:Type '{ buty: string[]; }' is missing the following properties from type 'string[]': length, pop, push, concat, and 26 more.(2322)

是否可能为这样的对象创建类型?

TypeScript Playground


@T.J. Crowder,我认为这不是同一个问题,原始问题涉及特定接口,而这个问题使用通用字符串键。我认为应该重新打开此问题,因为我相信没有人会通过使用您链接的那个解决此问题。 - Maciej Sikora
1个回答

7

以下解决方案基于映射类型:

type Test<T extends  { [key: string]: any }> =
    {
        [K in keyof T]:
            K extends 'name' ? { [key: string]: string[] } : string[]
    }

// id function to make type more accurate by generic
const makeTest = <T extends  { [key: string]: any }>(obj: Test<T>): Test<T> => obj
   

// correct use
const z = makeTest({
    name: { // this one is special
        buty: ['qqqq']
    },
    lipa: ['xxx'],
    // more keys here
});

// error as object wrong
const y = makeTest({
    name: ['xxx'], // no it is special
    lipa: ['xxx'],
    // more keys here
});

通过使用id函数(x => x),我们可以实现这个需求,该函数将通过使用泛型类型来缩小类型。当我们使用泛型时,TS的缩小效果更好,并且正是这个函数使其成为可能。此外,您制作的类型无法工作,因为'string |' name'键评估为'string',因此交集的第二部分完全被省略。
解决方案是使类型有条件地,并为特殊的“name”键设置不同的值类型。 playground

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接