How to declare a type for object with one different key in TypeScript

Viewed 728

Hello I want to create a type for an object like this:

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

Bacially it is an object like this

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

with one small exception. It always has a key name with a little bit different value.

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

but when I trying to merge these two types

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

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

I get an error Type '{ buty: string[]; }' is missing the following properties from type 'string[]': length, pop, push, concat, and 26 more.(2322).

Is it possible to create a type for an object like this?

TypeScript Playgroud

1 Answers

Below solution based on mapped types:

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
});

We can achieve the need by using id function (x => x) which will narrow the type thanks to use of generic type. TS has better narrowing when we use generics, and exactly this function allows us for that. Also the type you have made was not working because string | 'name' key evaluates into string therefore the second part of intersection was totally omitted.

The solution is to make the type conditional and for special 'name' key set different value type.

playground

Related