Home > Software engineering >  Typescript Type 'never': how to use for object fields?
Typescript Type 'never': how to use for object fields?

Time:10-01

I'm trying to get this example to work like this:

interface Foo {
    a: number;
    b: string;
    c: boolean;
}

type Explode<T> = keyof T extends infer K
    ? K extends unknown
    ? { [I in keyof T]: I extends K ? T[I] : never }
    : never
    : never;


type Test = Explode<Foo>;

const test: Test = {a: 1};

which gives me the following error:

Type '{ a: number; }' is not assignable to type '{ a: number; b: never; c: never; } | { a: never; b: string; c: never; } | { a: never; b: never; c: boolean; }'.
  Type '{ a: number; }' is missing the following properties from type '{ a: number; b: never; c: never; }': b, c

How can I instantiate an object of type Test without the error? I want a type that can contain either field a or b or c (or be an empty {}).

CodePudding user response:

I found the solution. I needed to make Foos fields optional like this:

EDITED to include the suggestion by @aprokryfos

interface Foo {
    a: number;
    b: string;
    c: boolean;
}

Now I can do:

interface Foo {
    a: number;
    b: string;
    c: boolean;
}

type AtMostOneOf<T> = keyof T extends infer K
    ? K extends unknown
    ? { [I in keyof T] ?: I extends K ? T[I] : never }
    : never
    : never;


type Test = AtMostOneOf<Foo>;

const test: Test = {a: 1}; // allowed
const test1: Test = {b: 'asd'}; // allowed
const test2: Test = {a: 1, b: 'asd'}; // not allowed
const test3: Test = {} // allowed

Playground

CodePudding user response:

You can define the Explode type as:


type Explode<T> = {
    [K in keyof T]: {
        [key in K]: T[K]
    }
}[keyof T]

then type Test will become:

type Test = {
    a: number;
} | {
    b: string;
} | {
    c: boolean;
}

TS Playground

  • Related