如何在TypeScript中使用一个不同的键声明对象的类型

Kon*_*zak 4 typescript

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

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

Run Code Online (Sandbox Code Playgroud)

Bacially 它是这样的对象

type Test = {
    [key: string]: string[]
}
Run Code Online (Sandbox Code Playgroud)

除了一个小例外。它总是有一个值略有不同的键名。

type Special = {
    name: {
        [key: string]: string[]
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

const z: Test = {
    name: { // this one is special
        buty: ['qqqq']
    },
    lipa: ['xxx'],
    // more keys here
};
Run Code Online (Sandbox Code Playgroud)

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

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

打字稿游乐场

Mac*_*ora 5

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

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
});
Run Code Online (Sandbox Code Playgroud)

我们可以通过使用 id 函数 (x => x) 来实现需求,这将由于使用泛型类型而缩小类型。当我们使用泛型时,TS 有更好的缩小范围,而正是这个功能允许我们这样做。此外,您制作的类型不起作用,因为string | 'name'键计算为string因此完全省略了交集的第二部分。

解决方案是使类型有条件,并为特殊的“名称”键设置不同的值类型。

操场