Home > other >  Typescript: Exclude undefined from union type
Typescript: Exclude undefined from union type

Time:10-15

There is a custom type Options (nested object) that I created. I want to use the type DefaultProperties to create an object that contains the default properties.

type Options = {
    id: number,
    text: string | undefined,
    properties: {
        title: string,
        subtitle: string | undefined,
    }
}

type DefaultProperties = Pick<Options, "properties">;

Of course the default properties cannot be undefined. So I want to exclude undefined from my union types. For that purpose there should be a build-in functions like NonNullable<T> or Exclude<T,UnionType>.

I tried three different ways to remove undefined but no solution is working with my type.

type Options = {
    id: number,
    text: string | undefined,
    properties: {
        title: string,
        subtitle: string | undefined,
    }
}

type DefaultProperties = Pick<Options, "properties">;


// Try #1: does not work
type Type1 = NonNullable<DefaultProperties>;

// Try #2: does not work
type NotOptional<Type> = {
    [Property in keyof Type]-?: Type[Property];
};
type Type2 = NotOptional<DefaultProperties>;

// Try #3: does not work
type Type3 = Exclude<Options, undefined>;

Example: TypeScript Playground

How can I remove all undefineds from all of my type union types?

Edit: All undefineds should be removed from my type. For example:

  • Options['text'] : string (No more undefined)
  • Options['properties']['subtitle'] : string (No more undefined)

Later I want to use the type for this (for example):

const options : Options = { ... };
const defaults: DefaultProperties= { ... }; // With no undefined

const node : HTMLElement = .... ;
node.innerHTML = options.properties.subtitle !== undefined ? options.properties.subtitle : defaults.properties.subtitle;

When defaults.properties.subtitle has the type string | undefined, the compiler throws an error because innerHTML only allows strings. For that I want to exclude undefined.

CodePudding user response:

You're really close with your NotOptional utility type and Exclude, the problem is that you're defining DefaultProperties as an object with a properties property, but you're trying to remove undefined from DefaultProperties, not from its properties property.

In a comment you've said you want DefaultProperties to be the same shape as properties on Options. That means the basic shape of it (before we try to remove undefined) is Options["properties"]. So:

type NotOptional<Type> = {
    [Property in keyof Type]: Exclude<Type[Property], undefined>;
};

type DefaultProperties = NotOptional<Options["properties"]>;

Tests:

const defaults1: DefaultProperties = {
    title: "foo",
    subtitle: undefined,    // <== Error as desired
};

const defaults2: DefaultProperties = {
    title: "foo",
    subtitle: "something",  // <== No error
};

Playground link

You might also consider removing optionality (combining two of the things you tried):

type NotOptional<Type> = {
    [Property in keyof Type]-?: Exclude<Type[Property], undefined>;
};

type DefaultProperties = NotOptional<Options["properties"]>;

Tests:

const defaults1: DefaultProperties = {
    title: "foo",
    subtitle: undefined,    // <== Error as desired (wrong type for `subtitle`)
};

const defaults2: DefaultProperties = {  // <== Error as desired (missing `somethingElse`)
    title: "foo",
    subtitle: "something",
};

const defaults3: DefaultProperties = {  // <== No error
    title: "foo",
    subtitle: "something",  // <== No error
    somethingElse: "x",
};

Playground link

  • Related