Home >Web Front-end >JS Tutorial >Optional vs. Undefined: How To Check for Optional Properties

Optional vs. Undefined: How To Check for Optional Properties

WBOY
WBOYOriginal
2024-07-28 02:36:43690browse

Optional vs. Undefined: How To Check for Optional Properties

In TypeScript, a property is considered optional if it can be omitted from an object, meaning it can be either undefined or not provided at all. Optional properties are denoted using the ? suffix on the property key. Determining whether a property is optional or explicitly defined with undefined as its type can be quite tricky.

Let's consider the following example with five possible combinations:

type Example = {
    required: number;
    optional?: number;
    requiredAsUndefined: undefined;
    requiredWithUndefined: number | undefined;
    optionalWithUndefined?: number | undefined;
}

The last four properties are allowed to be undefined, but only the second and fifth are actually optional. Interestingly, the properties optional, requiredWithUndefined, and optionalWithUndefined all resolve to the same union type number | undefined.

So, what we want is a type that returns true for optional and optionalWithUndefined, and false for the rest. Here's how such a utility type can look:

type IsOptional<T, K extends keyof T> = undefined extends T[K]
    ? ({} extends Pick<T, K> ? true : false)
    : false;

type Required = IsOptional<Example, 'required'>;  // false
type Optional = IsOptional<Example, 'optional'>;  // true
type RequiredAsUndefined = IsOptional<Example, 'requiredAsUndefined'>;  // false
type RequiredWithUndefined = IsOptional<Example, 'requiredWithUndefined'>;  // false
type OptionalWithUndefined = IsOptional<Example, 'optionalWithUndefined'>;  // true

There are two constraints in this utility type. The first constraint, undefined extends T[K], checks if undefined can be a part of the type accessed by T[K]. It essentially asks whether the type T[K] can include undefined. The second constraint, {} extends Pick ? true : false, ensures that the type {} (an empty object) is assignable to a type where the property K is picked, implying the property is optional.

From this utility type, we can build a new mapped type which only picks optional properties. The non-optional properties will be set to never:

type OptionalProperties<T> = {
    [K in keyof T]: IsOptional<T, K> extends true 
        ? T[K] 
        : never
}

type OnlyOptionals = OptionalProperties<Example>;
// type OnlyOptionals = {
//     required: never;
//     optional?: number;
//     requiredAsUndefined: never;
//     requiredWithUndefined: never;
//     optionalWithUndefined?: number | undefined;
// }

Having the properties with type never is usually enough for type safety, but in case we truly want to omit these properties for stylistic purposes, we can move the IsOptional extends true constraint into the square brackets. This is a nice little trick because it will set the key of non-optional properties to never, which will then get omitted by TypeScript automatically.

type OnlyOptionals<T> = {
    [K in keyof T as IsOptional<T, K> extends true ? K : never]: T[K]
} 
type OnlyOptionals = OnlyOptionals<Example>;
// type OnlyOptionals = {
//    optional?: number;
//    optionalWithUndefined?: number | undefined;
// }

Here's the Playground to try it out directly in the browser: TypeScript Playground

The above is the detailed content of Optional vs. Undefined: How To Check for Optional Properties. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn